وبلاگ جادی یکی از وبلاگهاییه که مرتب بهش سر میزنم و در واقع اولین جایی بود که من با زبان R آشنا شدم. ایشون تو وبلاگشان و سری ویدیوهای درک برنامهنویسی این مساله جالب را با پایتون حل کرده:
چی می شه اگر ۵۰ نفر در یک اتاق نفری ۱۰۰ دلار داشته باشن. در هر دور هر کس به شکل رندم یک نفر رو انتخاب می کنه و یک دلار از پولش رو به اون می ده. اگر پول کسی تموم بشه از بازی بیرون گذاشته می شه. بعد از بارها بازی کردن، وضعیت پول ها چطور خواهد بود؟
و از آن جایی که این مساله برای من خیلی جالب بود تصمیم گرفتم آن را با R حل کنم، فقط در نظر داشته باشید که من یک برنامهنویس به معنای واقعی نیستم و کدهای این پست ممکن است مشکلاتی اساسی داشته باشند.
برای حل این سوال اولین کاری که باید انجام دهیم ساخت آرایهای است که میزان پول هر یک از ۵۰ نفر در آن ذخیره شود:
people <- rep(100,50)
در قدم بعدی تابعی به نام بشکن تعریف میکنیم که به طور رندم از کسی که پولش هنوز صفر نشده یک دلار بگیرد و به شخص دیگری (که تا جایی که من از صورت مساله متوجه شدم او هم نباید پولش صفر شده باشد) بدهد. برای این کار از دو تابع sample و which استفاده میکنیم. تابع sample، یک نمونه تصادفی میگیرد و تابع which را برای این استفاده میکنیم که بتوانیم شرط صفر نبودن پول را پیاده کنیم. کل داستان را هم در یک حلقه مینویسیم و ورودی تابع ما به غیر از بردار people تعداد تکرارهای حلقه و خروجی تابع نیز بردار people خواهد بود:
beshkan <- function(n) { for(i in 1:n) { player <- sample(which( people > 0) , 2) people[player[1]] <<- people[player[1]] - 1 people[player[2]] <<- people[player[2]] + 1 } people }
در کد بالا به جای این که یک خط برای انتخاب شخصی که پول میدهد و یک خط برای شخصی که پول را میگیرد بنویسم با همان تابع sample یکباره دو عدد تصادفی تولید کردم. sample(which( people > 0 را میتوانید به این صورت بخوانید: از اعضای بردار people که برابر ۰ نیستند دو تا تصادفی انتخاب کن و شمارهی آنها را به من بده. نکته مهم دیگر هم این است که R ار ۱ شروع به شمردن میکند. در کد بالا به جای -> از ->> استفاده شده که متغیرهای درون تابع را از حالت محلی به حالت گلوبال تبدیل میکند. در واقع باعث میشود تاثیر دو خطی که مسوول کم و زیاد کردن پول هستند از تابع خارج شده و روی بردار poeple اعمال شود ( و با اتمام اجرای تابع از بین نرود.)
با ۱۰۰۰۰بار اجرای این تابع و استفاده از کدهای زیر، این نمودار حاصل میشود:
m <- beshkan(10000) barplot(sort(m))
که با جوابی که در ویدیو جادی بود تفاوت بسیاری دارد و هنوز پول یک نفر هم صفر نشده است. دو تا احتمال وجود دارد، احتمال اول تفاوت نحوه کار تابع sample در R و توابع تولید عدد تصادفی در پایتون است و احتمال دوم این است که من در جایی اشتباه کرده باشم (اگر فکر میکنید دومی محتملتر است حتما نظری برای این پست بگذارید). اگر به جای ۱۰۰۰۰ دفعه، حلقه درون تابع ۱۰۰۰۰۰ دفعه اجرا شود جواب من به جواب ویدیوی مورد نظر بسیار نزدیکتر میشود:
در پایان، چند خط کد به تابعی که نوشتیم اضافه میکنم تا در هر ۱۰۰ بار اجرا، یک نمودار بکشد و در یک فایل png ذخیره کند:
beshkan <- function(n) { for(i in 1:n) { player <- sample(which( people > 0) , 2) people[player[1]] <<- people[player[1]] - 1 people[player[2]] <<- people[player[2]] + 1 if(i %% 100 == 0) { png(paste(i,".png")) barplot(people , main = paste(i)) dev.off() } } people }
و با فایلهای ذخیره شده و با کمک نرمافزارهای جانبی، میتوان نمودار متحرک زیر را ساخت:
نوشته پیادهسازی قسمتهای ۱۵ و ۱۶ ویدیوهای درک برنامهنویسی جادی در R یا چی می شه اگر ۵۰ نفر در یک اتاق… اولین بار در use R. پدیدار شد.