سال 1410 است و برای همه دانشگاهها ابلاغیه آمده که باید تابلوهای اعلانات خود را الکترونیکی کنند. در بازار برنامههای مختلفی برای کار با تابلوهای الکترونیکی وجود دارد ولی دانشگاه شما میخواهد از برنامه متفاوتی استفاده کند و شما را به عنوان برنامه نویس آن انتخاب کرده است.
نمونهای از تابلو اعلانات موجود رو میتونید [اینجا](https://s7.picofile.com/file/8238595068/%db%b2%db%b0%db%b1%db%b6%db%b0%db%b2%db%b0%db%b8_%db%b1%db%b2%db%b5%db%b3%db%b1%db%b4.jpg) ببینید
# جزئیات پروژه
پروژهی اولیه را از [این لینک](/contest/assignments/53485/download_problem_initial_project/181481/) دانلود کنید. ساختار فایلهای پروژه به صورت زیر است:
```
.
├── go.mod
├── go.sum
├── main.go
└── main_sample_test.go
```
در فایل `main.go` چند تابع و متد وجود دارد که شما باید آنها را کامل کنید.
از شما خواسته شده که نحوه اضافه کردن اعلامیه به تابلو و برداشتن آن از روی تابلو شبیه تابلوهای فیزیکی موجود باشد تا شکل و شمایل آشنای خود را حفظ کند. به این معنی که ممکن است اعلامیهها روی هم قرار بگیرند و اگر بخواهیم اعلامیه زیرین را از روی تابلو حذف کنیم، باید ابتدا اعلامیههای روی آن برای لحظهای برداشته شوند و سپس دوباره سر جایشان گذاشته شوند. همچنین تمام اعلانات یک عدد منحفصر به فرد (ID) دارند.
## آنچه باید پیادهسازی کنید
در وهله اول به شما اینترفیس تابلو و اعلانات روی آن داده شده است. (به توضیحات راجع به این توابع بعدا پرداخته خواهد شد)
```go main.go
type AnnouncementBoard interface {
getAnnouncementIDsAt(int, int) []int
}
type AnnouncementPaper interface {
addTo(AnnouncementBoard, int, int) error
removeAndGetIDsOnTop() []int
}
```
همچنین نیاز است برای تابلو و اعلانات توابعی با امضاهای زیر تعریف کنید که به عنوان تابع سازنده (constructor) عمل میکنند. تضمین میشود در تستها از خروجی همین توابع استفاده خواهد شد.
```go main.go
func NewBoard(row int, col int) AnnouncementBoard {
}
func NewPaper(width int, height int, ID int) AnnouncementPaper {
}
```
تابع `NewBoard`: این تابع تعداد ردیفها و تعداد ستونهای تابلو را به عنوان ورودی میگیرد و یک شی از نوع AnnouncementBoard برمیگرداند.
تابع `NewPaper`: این تابع عرض (تعداد ستونهایی که روی تابلو اشغال میکند) و طول (تعداد ردیفهایی که روی تابلو اشغال میکند) و آیدی اعلان را به عنوان ورودی میگیرد و یک شی از نوع AnnouncementPaper برمیگرداند. تضمین میشود که عرض تمام اعلانات عددی فرد است.
### متدهای اینترفیسها
تابع `getAnnouncementIDsAt`: این تابع به ترتیب شماره یک ردیف و شماره یک ستون از تابلو را میگیرد و آیدی اعلانات موجود در این نقطه را به ترتیب از زیرترین اعلان به روترین آن برمیگرداند.
تابع `addTo`: اعلامیه را به تابلویی که به عنوان ورودی میگیرد میچسباند. رو مقدار بعدی در ورودی به ترتیب ردیف و ستونی است که پونز در آن قرار خواهد گرفت. (ردیف و ستون اینجا از 0 شمرده میشوند. مثلا اگر در تابع `NewBoard` تعداد ردیف را 5 داده باشیم، اینجا اگر بخواهیم پونز روی ردیف اول باشد عددش را 0 میدهیم و اگر بخواهیم روی ردیف آخر باشد عددش را 4 میدهیم.) موقعیت پونز روی کاغذ ستون وسط و بالاترین ردیف است. یعنی اگر عرض کاغذ 3 و طول آن 4 باشد، یعنی کاغذ 3 ستون و 4 ردیف از تابلو را اشغال کند، پونز روی ردیف اول (از بالا) و ستون دوم قرار میگیرد. (یادآوری: تضمین میشود عرض کاغذ عددی فرد است)
همچنین در این تابع باید چک کنید که نه پونز و نه خود کاغذ از تابلو بیرون نزنند و اگر زدند یک `error` برگردانید (پیام درون ارور مهم نیست)
و دقت کنید که در تابع `getAnnouncementIDsAt` فقط پونزهایی که در آن نقطه قرار دارند را نمیخواهیم. هر قسمتی از هر کاغذی در آن نقطه از تابلو قرار داشته باشند باید آیدیش در لیست خروجی آن تابع در جای درستش باشد.
همچنین تضمین میشود هر شی که از تابع `NewPaper` برگردانده میشود، در هر لحظه فقط و فقط به یک تابلو وصل خواهد شد. البته میتوان از روی یک تابلو آن را برداشت و سپس روی تابلوی دیگری نصب کرد.
تابع `removeAndGetIDsOnTop`: وقتی این تابع روی یک اعلان صدا میشود، آن اعلان و تمام اثراتش باید از روی تابلویی که در حال حاضر رویش قرار دارد حذف شود. همچنین باید این تابع لیستی از اعلاناتی که رویا این اعلان قرار دارند را برگرداند (همان داستان که میخواهیم مثل تابلوی فیزیکی اول اعلانات رویش را برداریم تا به ایت اعلان برسیم و بعد آن روییها را سر جایشان برگردانیم).
البته این تابع یک چالش دارد که اگر پیاده سازیش نکنید فقط بخشی از نمره اسن قسمت را میگیرید. آن هم این است که این اعلانات باید به ترتیب از روترین اعلان به زیرترین مرتب شود. برای اعلاناتی که باید برداشته شوند ولی به هم ارجعیتی ندارند (هیچکدام روی دیگری نیست)، مهم نیست با چه ترتیبی در خروجی قرار میگیرند.
برای مثال اگر یک اعلان با آیدی 200 را بخواهیم حذف کنیم، در حالی که یک اعلان با آیدی 150 روی گوشه راست بالای آن قرار دارد و اعلان با آیدی 250 روی گوشه سمت چپ آن، در حالی که 150 و 250 با هم هیچ هم پوشانی ندارند، مهم نیست خروجی [150 250] است یا [250 150]. ولی اگر 200 را بخواهیم حذف کنیم در حالیکه 150 روی گوشه راست بالای 200 قرار داشته باشد و 250 گوشه راست بالای 150، خروجی باید باشد [150 250]، یعنی خانه 0 آن 250 و خانه 1 آن 150 باشد.
# آنچه باید آپلود کنید
پس از پیادهسازی توابع خواسته شده، فایل `main.go` را آپلود کنید.