PDA

View Full Version : بازی چکرز با الگوریتم minimax با یک عمق برای یادگیری



Salazar.mi
سه شنبه 07 آبان 1398, 13:32 عصر
$w0=10;
$w1=50;
$w2=-30;
$v=$w0+($w1*$x1)+($w2*$x2);

if($a['sotoon'.$i]["kh".$j]===2)
{

if(isset($a['sotoon'.($i+1)]["kh".($j+1)]))
{
if($a['sotoon'.($i+1)]["kh".($j+1)]===0)
{
$a['sotoon'.$i]["kh".$j]=0;
$a['sotoon'.($i+1)]["kh".($j+1)]=2;

}
}


}


اجازه بدین من کلا بگم هدف چیه
تا شما دوستان با توجه به اطلاعاتتون به من خنگ کمک کنید از دستم راحت شید
من همه کد قبلیا را پاک کردم
الان این را دارم

ببینید
این بازی چکرز برای درس یادگیری طبق الگوریتم minmax با عمق یک
چیزی که من فهمیدم اینه در هر لحظه
نوبت هرکی هست
باید بیایم از دیدگاه اون تمام حرکت های ممکن را برسی کنیم
به ازای هر حرکت جدید یه v داریم v ارزش صفحه بازی هست
v های جدید را با v قبلی مقایسه میکنیم
اگر v جدیدی نبود و تمام v های بدست اومده با v قبلی برابر بود
رندوم یکیشو انتخاب میکنیم و حرکتشو انجام میدیم
اگر v جدید داشتیم میایم vجدید را از v قدیم کم میکنیم یه مقداری بدست میاریم که میشه error
حالا طبق این فرمول w ها را تغییر میدیم
wجدید=wقدیم +0.1*تعداد مهره های همون w * مقدار errror
مثلا برای w1 تعداد مهره های 1 میشه همون x1 در واقع میشه تعداد خانه هایی که مقدار یک دارن
تا جایی انجام میدیم که مقدار v بشه 100 یا -100 یا 0
این همه آن چیزی بود که باید بنویسم
من اینجوری گفتم
گفتم با اون دوتا حلقه for تو در تو میام به هر خانه دسترسی پیدا میکنیم
بعد مثلا نوبت شماره های 2 است
تمام حالت هایی که 2 بتونه انجام بده را در نظر میگیریم
شما فرض کنید شماره دو فقط در صورتی که خونه سطر بعد و ستون بعدش 0 باشه میتونه بره در آن خانه قرار بگیرد که در این صورت خودش مقدارش میشه 0 خونه سطر بعد و ستون بعدش میشه 2
(که من حتی این حرکت را نمیتونم بنویسم خودش میشه صفر ولی دوتا خونه سطر بعد و ستون بعدش میشه2 )
الان باید بیام به ازای هر خونه ای که میتونه این حرکت را انجام بده بیا v راجدا حساب کن با v قبلی مقایسه کن
و
...
الان اگر درست فهمیده باشم باید اول توی اون دوتا حلقه for تو در تو تمام حرکات ممکن برای مثلا مهره های 2 حساب کنم بزارم توی تابع
همونجا باید فرمول v را هم حساب کنم و مقایسه را انجام بدم
ولی من حتی نمیتونم تابع حرکت را بنویسم
خواهشا کمکم کنید
اگرم به نظرتون نشدنیه بگین لطفا
ممنون میشم

Salazar.mi
سه شنبه 07 آبان 1398, 15:49 عصر
میگم من یه چیزی بگم
آقای ali_sed (https://barnamenevis.org/member.php?19568-ali_sed)
اگر بخواهیم دقیقیا طبق هر چیزی که شما لطف کردین و گفتین پیش بریم
آیا میشه بعد از اون دوتا حلقه foreach به مقدارهای سطر بعد و ستون بعد دسترسی پیدا کرد


<?php
$a=array(
array(2,5,2,5,0,5,1,5,),
array(2,5,2,5,0,5,1,5,),
array(2,5,2,5,0,5,1,5,),
array(2,5,2,1,0,5,1,5,),
array(2,5,2,5,0,5,1,5,),
array(2,5,2,5,0,5,1,5,),
array(0,5,0,5,0,5,1,5,),
array(0,5,0,5,0,5,1,5,),

);


$red=0;
array_walk_recursive($a, function($v) use(&$red){ if($v==2) {++$red;}});
echo $red;
echo '<br>';
$blue=0;
array_walk_recursive($a, function($v) use(&$blue){ if($v==1) {++$blue;}});
echo $blue;




$w0=-10;
$w1=50;
$w2=-30;
$v=$w0+($w1*$blue)+($w2*$red);
echo '<br>';
echo $v;


$find = new stdClass();
foreach($a as $i=>$row){
foreach($row as $j=>$data){
if($data===1){
$v=$w0+($w1*$blue)+($w2*$red);
if(!isset($find->value) || $v > $find->value){
$find->value = $v;
$find->i = $i;
$find->j = $j;
}
}
}
}

var_dump($find );
?>

یعنی تو خط 37 شرط && بزاریم بگیم هر خونه ای که سطر بعد و ستون بعدش 0 باشه؟؟؟؟؟؟؟؟

ali_sed
سه شنبه 07 آبان 1398, 21:59 عصر
چند نکته هست اول اینکه فقط سطر و ستون بعد کافی نیست. سطر جلویی یه ستون قبل و یه ستون بعد را باید بررسی کنید. چون هر مهره میتونه به صورت اریب به چپ و یا راست حرکت کنه. البته باید حالت های استثنا هم در نظر بگیرید مثلا وقتی که مهره در ستون 0 هست دیگه به سمت چپ نمیتونه بره. بنابراین فقط مهره مهم نیست بلکه شما باید حرکت های مجاز را در نظر بگیرید و برای هر کدام v را محاسبه و بررسی کنید. بنابراین بجای اینکه تنها موقعیت مهره را ذخیره کنید بهتر است موقعیت خانه هدف را نیز همان موقع ذخیره کنید. متاسفانه درس یادگیری ماشین نداشتم وگرنه بیشتر کمکتان می کردم.



// مهره ما در خانه ij قرار دارد.
$data = $a[$i][$j]
//یک بار برای خانه جلو سمت راست بررسی کنید.
$target = $a[$i+1][$j+1];

$find->value = $v;
$find->i = $i;
$find->j = $j;
find->target_i = $i+1;
$find->target_j = $j+1;

//یک بار هم برای خانه جلو سمت چپ بررسی کنید.
$target = $a[$i+1][$j-1];

$find->value = $v;
$find->i = $i;
$find->j = $j;
find->target_i = $i+1;
$find->target_j = $j-1;



(به آی و جی خودتان دقت کنید من نمیدونم کدام سطر کدام ستون است. در ضمن برای یک بازیکن اگر سطر جلو i+1 باشد برای حریف او سطر جلو باید i-1 در نظر گرفته شود)

قبلا به دنبال یک مهره بود ولی الان به دنبال یافتن حرکت مناسب هستیم بنابراین بجای $find از نام $move استفاده کنیم با معنی تر است.

Salazar.mi
چهارشنبه 08 آبان 1398, 15:28 عصر
چند نکته هست اول اینکه فقط سطر و ستون بعد کافی نیست. سطر جلویی یه ستون قبل و یه ستون بعد را باید بررسی کنید. چون هر مهره میتونه به صورت اریب به چپ و یا راست حرکت کنه. البته باید حالت های استثنا هم در نظر بگیرید مثلا وقتی که مهره در ستون 0 هست دیگه به سمت چپ نمیتونه بره. بنابراین فقط مهره مهم نیست بلکه شما باید حرکت های مجاز را در نظر بگیرید و برای هر کدام v را محاسبه و بررسی کنید. بنابراین بجای اینکه تنها موقعیت مهره را ذخیره کنید بهتر است موقعیت خانه هدف را نیز همان موقع ذخیره کنید. متاسفانه درس یادگیری ماشین نداشتم وگرنه بیشتر کمکتان می کردم.



// مهره ما در خانه ij قرار دارد.
$data = $a[$i][$j]
//یک بار برای خانه جلو سمت راست بررسی کنید.
$target = $a[$i+1][$j+1];

$find->value = $v;
$find->i = $i;
$find->j = $j;
find->target_i = $i+1;
$find->target_j = $j+1;

//یک بار هم برای خانه جلو سمت چپ بررسی کنید.
$target = $a[$i+1][$j-1];

$find->value = $v;
$find->i = $i;
$find->j = $j;
find->target_i = $i+1;
$find->target_j = $j-1;



(به آی و جی خودتان دقت کنید من نمیدونم کدام سطر کدام ستون است. در ضمن برای یک بازیکن اگر سطر جلو i+1 باشد برای حریف او سطر جلو باید i-1 در نظر گرفته شود)

قبلا به دنبال یک مهره بود ولی الان به دنبال یافتن حرکت مناسب هستیم بنابراین بجای $find از نام $move استفاده کنیم با معنی تر است.

سلام
من میخواستم طبق گفته های شما پیش برم ولی نتونستم الان به نظر شما این درسته؟
طبق نتیجه var_dump اومده اول یکی از یک هارا صفر کرده بعد رفته سراغ یک بعدی
یعنی همون چیزی که ما میخوایم
اما من میخوام به ازای هر کدوم بیاد v را حساب کنه (کجا باید بگم بیاد v را حسا کنه که بشه همینی که میخوام)؟؟؟؟؟؟
اگر v جدید با v قبلی برابر نبود error را حساب کنه و w ها را به روز کند
اگر هم یکی بود از بینشون random یکی را انتخاب کند
قسمت random را نمیدونم چجوری بگم از بین اونایی که این شرایط را دارن یکی را انتخاب کن
بله متوجه هستم که باید سطر بعد و ستون قبل را هم در نظر بگیرم
گفتم فعلا یک حرکت را بنویسم ببینم اصلا امکانش هست
ممنون میشم کمکم کنید
من سعی کردم هر چیزی که تو پست اول گذاشتم را برای یک حرکت به سمت سطر بعد و ستون بعد بنویسم
ولی قسمت random را نتونستم
امیدوارم منظورمو متوجه شده باشید
لطفا اگر با روش خودتون قابل انجام هست برای همین یه حرکت میشه بنویسید
ممنون میشم
این آرایه ای که مثال زدم


$a=array(
array(1,2,2,1,2),
array(2,0,2,2,0),
array(2,2,0,2,2),
array(2,2,2,2,2),

);



این کدی که نوشتم


foreach($a as $i=>$row){
foreach($row as $j=>$data){
if(isset($a[$i+1][$j+1]))
{
$db=$a[$i+1][$j+1];
}
$r=1;
if($data===1 && $db===0){
if(isset($a[$i+1][$j+1]))
{
$a[$i+1][$j+1]=1;
$a[$i][$j]=0;

}
$vj=$w0+($w1*$blue)+($w2*$red);
if($vj != $v)
{
$error=$vj-$v;
$w1=$w1+0.1*$blue*$error;
$w2=$w2+0.1*$red*$error;
}
else
{
$r++;
$rand=rand(1,$r);
echo $rand;

}


//var_dump($a);
}
}
}


اینم نتیجه خروجی


array (size=4)
0 =>
array (size=5)
0 => int 0
1 => int 2
2 => int 2
3 => int 1
4 => int 2
1 =>
array (size=5)
0 => int 2
1 => int 1
2 => int 2
3 => int 2
4 => int 0
2 =>
array (size=5)
0 => int 2
1 => int 2
2 => int 0
3 => int 2
4 => int 2
3 =>
array (size=5)
0 => int 2
1 => int 2
2 => int 2
3 => int 2
4 => int 2
-360
C:\wamp64\www\neww\27\page game.php:49:
array (size=4)
0 =>
array (size=5)
0 => int 0
1 => int 2
2 => int 2
3 => int 0
4 => int 2
1 =>
array (size=5)
0 => int 2
1 => int 1
2 => int 2
3 => int 2
4 => int 1
2 =>
array (size=5)
0 => int 2
1 => int 2
2 => int 0
3 => int 2
4 => int 2
3 =>
array (size=5)
0 => int 2
1 => int 2
2 => int 2
3 => int 2
4 => int 2

ولی اگر var_dump را بزارم آخرین کد بیرون از همه آکولادها مستقیم یه آرایه نشان میده که دوتا عدد باهم تغییر کرده
من گیج شدم نمیدونم
random کجا باید قرار بگیرد
گفتم شاید با دستور next() بشه خانه به خانه جلو رفت و اگر حرکتی میتونه انجام بده بیاد فرمول v را حساب کنه اگر هم نه همینجوری بره جلو
ولی نتونستم دستور next را برای آرایه دو بعدی بنویسم
به نظر شما next راه خوبی هست؟
اصلا امکانش هست؟

ali_sed
چهارشنبه 08 آبان 1398, 21:00 عصر
خسته نباشید.

نیازی به دستور نکست ندارید همین الان دارید داخل دو تا حلقه تو در تو تک تک خانه های بورد را بررسی می کنید. مثلا اگر مهره آبی بود و خانه جلوییش (راست جلو) خالی بود یک حرکت قابل قبول است. حرکت را بصورت موقت انجام داده (برای بررسی حرکت مجاز بعدی نباید تغییری در مهره های بورد اصلی صورت گیرد) و مقدار V را محاسبه می کنیم. من متوجه شیوه محاسبه فرمول v نشدم اینکه مقدار اولیه برای v و w0 و ... چیست.

اما در هر صورت من فرض می کنم مقدار v اولیه برابر -100 باشه.



<?php
$a=array(
array(2,5,2,5,0,5,1,5,),
array(2,5,2,5,0,5,1,5,),
array(2,5,2,5,0,5,1,5,),
array(2,5,2,1,0,5,1,5,),
array(2,5,2,5,0,5,1,5,),
array(2,5,2,5,0,5,1,5,),
array(0,5,0,5,0,5,1,5,),
array(0,5,0,5,0,5,1,5,),

);


$w0=-10;
$w1=50;
$w2=-30;
$v=$w0+($w1*$blue)+($w2*$red);
$move = [];

foreach($a as $i=>$row){
foreach($row as $j=>$data){
if(isset($a[$i+1][$j+1]))
{
$db=$a[$i+1][$j+1];
}
$r=1;
if($data===1 && $db===0){
if(isset($a[$i+1][$j+1]))
{
//چون نباید بورد اصلی تغییر کند و این حرکت تنها جهت محاسبه وی است بورد را در یک متغییر موقت میریزیم
$tmp = $a;
$tmp[$i+1][$j+1]=1;
$tmp[$i][$j]=0;

//توجه کنید که در هر حرکت ممکن است تعداد مهره ها تغییر کنید پس باید دوباره شمرده شود
$red=0;$blue=0;
array_walk_recursive($tmp, function($val) use(&$red){ if($val==2) {++$red;}elseif($val==1) {++$blue;}});


$vj=$w0+($w1*$blue)+($w2*$red);
if($vj > $v)
{
$error=$vj-$v;
$w1=$w1+0.1*$blue*$error;
$w2=$w2+0.1*$red*$error;
$v = $vj;
//ذخیره اطلاعات مربوط به حرکت تا بعدا روی بورد اصلی این حرکت پیاده شود
$move = [$i, $j, $i+1, $j+1];
}

}
}
}
}

var_dump($v);
var_dump($move);
//بهترین حرکت مورد انتخاب شده روی بورد اصلی پیاده شود
if($move){
//جای دو خانه را با هم عضو کن
$tmp = $a[$move[0]][$move[1]];
$a[$move[0]][$move[1]] = $a[$move[2]][$move[3]];
$a[$move[2]][$move[3]] = $tmp;
unset($tmp);
}

Salazar.mi
چهارشنبه 08 آبان 1398, 21:30 عصر
خسته نباشید.

نیازی به دستور نکست ندارید همین الان دارید داخل دو تا حلقه تو در تو تک تک خانه های بورد را بررسی می کنید. مثلا اگر مهره آبی بود و خانه جلوییش (راست جلو) خالی بود یک حرکت قابل قبول است. حرکت را بصورت موقت انجام داده (برای بررسی حرکت مجاز بعدی نباید تغییری در مهره های بورد اصلی صورت گیرد) و مقدار V را محاسبه می کنیم. من متوجه شیوه محاسبه فرمول v نشدم اینکه مقدار اولیه برای v و w0 و ... چیست.

اما در هر صورت من فرض می کنم مقدار v اولیه برابر -100 باشه.



<?php
$a=array(
array(2,5,2,5,0,5,1,5,),
array(2,5,2,5,0,5,1,5,),
array(2,5,2,5,0,5,1,5,),
array(2,5,2,1,0,5,1,5,),
array(2,5,2,5,0,5,1,5,),
array(2,5,2,5,0,5,1,5,),
array(0,5,0,5,0,5,1,5,),
array(0,5,0,5,0,5,1,5,),

);


$w0=-10;
$w1=50;
$w2=-30;
$v=$w0+($w1*$blue)+($w2*$red);
$move = [];

foreach($a as $i=>$row){
foreach($row as $j=>$data){
if(isset($a[$i+1][$j+1]))
{
$db=$a[$i+1][$j+1];
}
$r=1;
if($data===1 && $db===0){
if(isset($a[$i+1][$j+1]))
{
//چون نباید بورد اصلی تغییر کند و این حرکت تنها جهت محاسبه وی است بورد را در یک متغییر موقت میریزیم
$tmp = $a;
$tmp[$i+1][$j+1]=1;
$tmp[$i][$j]=0;

//توجه کنید که در هر حرکت ممکن است تعداد مهره ها تغییر کنید پس باید دوباره شمرده شود
$red=0;$blue=0;
array_walk_recursive($tmp, function($val) use(&$red){ if($val==2) {++$red;}elseif($val==1) {++$blue;}});


$vj=$w0+($w1*$blue)+($w2*$red);
if($vj > $v)
{
$error=$vj-$v;
$w1=$w1+0.1*$blue*$error;
$w2=$w2+0.1*$red*$error;
$v = $vj;
//ذخیره اطلاعات مربوط به حرکت تا بعدا روی بورد اصلی این حرکت پیاده شود
$move = [$i, $j, $i+1, $j+1];
}

}
}
}
}

var_dump($v);
var_dump($move);
//بهترین حرکت مورد انتخاب شده روی بورد اصلی پیاده شود
if($move){
//جای دو خانه را با هم عضو کن
$tmp = $a[$move[0]][$move[1]];
$a[$move[0]][$move[1]] = $a[$move[2]][$move[3]];
$a[$move[2]][$move[3]] = $tmp;
unset($tmp);
}

سلامت باشید.
بی نهایت ممنونم که جواب دادین
راستش من باید چیزی که شما نوشتین چندین بار بخوانم
فقط در جواب بگم
متغیر v داره ارزش صفحه را میگه
و w ها یه سری وزن اند که به هر گروه مهره داده میشه
هر بار میاد متغیر v را میسنجه اگر همه حرکت ها برابر با حالت قبلی بود از بینشون random یه حرکت را انجام میده
اگر v با قبلی برابر نبود با v قبلی میسنجه اگر مقدارش بیشتر بود v جدید انتخاب میشه
بعد مقدار error را حساب میکنه
با error میاد مقدار w ها را به روز میکند
این کار را انقدر انجام میده تا بهترین w ها پیدا بشن
بی نهایت ممنونم که جواب دادین
خدا خیرتون بده دعا میکنم هرچی میخواین خدا بهتون بده
شرمندم ولی اگر امکانش براتون بود میشه در مورد قسمت randomاشم یه راهنمایی بفرمایید
بازم بی نهایت تشکر میکنم
شرمندم خیلی اذیتتون کردم
بازم ممنونم

ali_sed
چهارشنبه 08 آبان 1398, 22:00 عصر
البته $a هم باید اصلاح بشه کلا 0 خالی 1 آبی 2 قرمز:


$a = [
[0,2,0,2,0,2,0,2],
[2,0,2,0,2,0,2,0],
[0,2,0,2,0,2,0,2],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[1,0,1,0,1,0,1,0],
[0,1,0,1,0,1,0,1],
[1,0,1,0,1,0,1,0],
];

ali_sed
چهارشنبه 08 آبان 1398, 22:27 عصر
خب آخرش نگفتید وقتی هنوز بازی شروع نشده چه مقداری برای v w0 w1 w2 باید در نظر بگیریم و چرا؟ چون v وابسته به مقادیر w0 w1 w2 می باشد.

تا جایی که من متوجه شدم اول بازیکن آبی شروع می کنه (یک انسان) حالا برنامه (قرمز) قراره بهترین حرکت مناسب را پیدا کنه (برای سادگی تنها یک عمق در نظر گرفته شده است). فرض کنیم بازیکن قرمز 8 حرکت مجاز دارد برای هر حرکت مقدار V را محاسبه می کنیم و بزرگترین آن را پیدا می کنیم اگر چند حرکت V برابر داشتند رندوم یکی را انتخاب کنه. مثلا ممکنه برای دو حرکت مقدار V = 10 باشد و برای 6 حرکت دیگر برابر 5 باشد لذا باید از بین دو حرکت یکی بصورت دندوم انتخاب شود.

اگر اینطور باشه شما می توانید تمامی حرکات با V برابر را در یک آرایه بریزید و بعد یکی را بصورت رندوم انتخاب کنید. یا اینکه دو به دو یکی را رندوم انتخاب کنید.یعنی اینجوری:


if($vj > $v || ($vj == $v && rand(0,1)))
{
$error=$vj-$v;
$w1=$w1+0.1*$blue*$error;
$w2=$w2+0.1*$red*$error;
$v = $vj;
//ذخیره اطلاعات مربوط به حرکت تا بعدا روی بورد اصلی این حرکت پیاده شود
$move = [$i, $j, $i+1, $j+1];
}


فرض کنیم اولین حرکت انتخاب شده است برای حرکت مجاز بعدی وی را محاسبه می کنیم و برابر وی قبلی می شود. rand(0,1) - یا صفر است یا یک - اگر یک بود حرکت منتخب را عوض می کند و اگر صفر بود همان حرکت قبلی را نگه می دارد. اگر وی حرکت سوم نیز برابر شد تنها بین حرکت منتخب با این حرکت جدید دوباره یکی را بصورت رندوم انتخاب می کنیم و الی آخر. این حالت پیاده سازیش خیلی راحت تره ولی دقت کنید که میزان شانس انتخاب عناصر با این روش برابر نیست.

سوالم من اینه:
الان قرمز (کامپیوتر) حرکت منتخب را انجام میدهد و نوبت بازیکن آبی هست که یک شخص آن را انجام میدهد و دوباره نوبت برنامه می شود درسته؟
حالا که نوبت برنامه شد آیا از V حرکت قبلی بازیکن قرمز برای یافتن حرکت جدید استفاده می کنیم یا نه؟

Salazar.mi
چهارشنبه 08 آبان 1398, 23:19 عصر
خب آخرش نگفتید وقتی هنوز بازی شروع نشده چه مقداری برای v w0 w1 w2 باید در نظر بگیریم و چرا؟ چون v وابسته به مقادیر w0 w1 w2 می باشد.

تا جایی که من متوجه شدم اول بازیکن آبی شروع می کنه (یک انسان) حالا برنامه (قرمز) قراره بهترین حرکت مناسب را پیدا کنه (برای سادگی تنها یک عمق در نظر گرفته شده است). فرض کنیم بازیکن قرمز 8 حرکت مجاز دارد برای هر حرکت مقدار V را محاسبه می کنیم و بزرگترین آن را پیدا می کنیم اگر چند حرکت V برابر داشتند رندوم یکی را انتخاب کنه. مثلا ممکنه برای دو حرکت مقدار V = 10 باشد و برای 6 حرکت دیگر برابر 5 باشد لذا باید از بین دو حرکت یکی بصورت دندوم انتخاب شود.

اگر اینطور باشه شما می توانید تمامی حرکات با V برابر را در یک آرایه بریزید و بعد یکی را بصورت رندوم انتخاب کنید. یا اینکه دو به دو یکی را رندوم انتخاب کنید.یعنی اینجوری:


if($vj > $v || ($vj == $v && rand(0,1)))
{
$error=$vj-$v;
$w1=$w1+0.1*$blue*$error;
$w2=$w2+0.1*$red*$error;
$v = $vj;
//ذخیره اطلاعات مربوط به حرکت تا بعدا روی بورد اصلی این حرکت پیاده شود
$move = [$i, $j, $i+1, $j+1];
}


فرض کنیم اولین حرکت انتخاب شده است برای حرکت مجاز بعدی وی را محاسبه می کنیم و برابر وی قبلی می شود. rand(0,1) - یا صفر است یا یک - اگر یک بود حرکت منتخب را عوض می کند و اگر صفر بود همان حرکت قبلی را نگه می دارد. اگر وی حرکت سوم نیز برابر شد تنها بین حرکت منتخب با این حرکت جدید دوباره یکی را بصورت رندوم انتخاب می کنیم و الی آخر. این حالت پیاده سازیش خیلی راحت تره ولی دقت کنید که میزان شانس انتخاب عناصر با این روش برابر نیست.

سوالم من اینه:
الان قرمز (کامپیوتر) حرکت منتخب را انجام میدهد و نوبت بازیکن آبی هست که یک شخص آن را انجام میدهد و دوباره نوبت برنامه می شود درسته؟
حالا که نوبت برنامه شد آیا از V حرکت قبلی بازیکن قرمز برای یافتن حرکت جدید استفاده می کنیم یا نه؟
بی نهایت سپاسگذارم از این همه توجه شما
حقیقتش باید اول برنامه ای نوشته بشه که هم مهره آبی و هم مهره قرمز هردو را کامپیوتر انجام بده تا یادگیری انجام بشه اصطلاحا میگن train
به ما گفتن برای قسمت یادگیری بیاین قوانین را برای یک بازی بنویسین
طبق این قوانین همانطور که خودتون گفتین امکان داره wها تغییر کنند یا که نه تغییر نکنند
در نهایت آخر هر بازی زمانی هست که
یا v=100 مثلا بازیکن اول برده
یا v=-100 بازیکن دوم برده
یا v=0 مساوی شده
در نهایت آخر هر بازی ما یه سری w جدید داریم میایم برنامه ای که برای یک بازی نوشتیم را تو یه حلقه while میذاریم تا1000 بار برنامه تکرار بشه و هر بار از wقبلی برای w جدید استفاده میکنیم و بهترین w ها پیدا بشن
بعد با بهترین w میریم برای قسمت تست
که یک سمت کامپیوتر و یک سمت خودمون قرار داریم
حالا که نوبت برنامه شد آیا از V حرکت قبلی بازیکن قرمز برای یافتن حرکت جدید استفاده می کنیم یا نه؟
در جواب این سوال باید بگم طبق چیزی که من فهمیدم v ارزشی هست که به صفحه داده میشه
هر دفعه از همون v قبلی استفاده میشه
اما مهم اینه که اگر بازیکن max باشه مثلا مهره آبی باید از بین v ها max را انتخاب کنه
و اگر بازیکن min باشه مثلا مهره قرمز باید از بین v ها min را انتخاب کنه
خب آخرش نگفتید وقتی هنوز بازی شروع نشده چه مقداری برای v w0 w1 w2 باید در نظر بگیریم و چرا؟ چون v وابسته به مقادیر w0 w1 w2 می باشد.
و در جواب این سوال به ما گفتن بیاین در ابتدا یه مقدار پیش فرضی را به wها بدین
ولی مثلا اگر مهره آبی max بیاین به w متناظر با مهره آبی عدد بیشتر بدین تا به w2
فکر کنم همه چیز را درباره بازی به شما گفتم فقط دو نکته را نگفتم
زدن مهره حریف:هر مهره در صورتی که مهره ای که به صورت اریب در مقابلش قرارا دارد مهره حریف باشه و خانه ای که به صورت اریب بعد از مهره حریف قرار داره خالی باش میتونه از خانه خودش بره در خانه خالی قرار بگیرد با اینکار مهره حریف حذف میشه
مهره شاه: هر مهره میتونه فقط به صورت اریب به سمت جلو بره ولی اگر مثلا مهره های آبی پایین صفحه هستند بتونن خودشونو به بالاترین سطر صفحه برسونن تبدیل به مهره شاه میشن و میتونن به سمت عقب هم به صورت اریب حرکت کنند
بی نهایت ممنونم که جواب دادین
بی نهایت ممنونم
نمیدونم چجوری جبران کنم
امیدوارم هرچیزی دوست دارین خدا بهتون بده
واقعا ممنونممم

Salazar.mi
چهارشنبه 08 آبان 1398, 23:34 عصر
یه چیزی بپرسم
الان یعنی این یه جمله که نوشتین


($vj == $v && rand(0,1)


میاد میگه اگر vها برابر بود rand استفاده کن
اگر random صفر بود خودشو بزار
اگر random یک بود تغییر بده
شرمندم دارم دوباره میپرسم
:متعجب:

ali_sed
پنج شنبه 09 آبان 1398, 00:09 صبح
در پایین همان قسمت توضیح دادم: با توجه به اینکه در هر مرحله یک v ساخته می شود برای اینکه بین چند تا یکی را رندوم انتخاب کنیم تا زمانی که همه ساخته نشده اند نمیتوان رندوم انتخاب کرد پس باید همه را در یک آرایه ذخیره کنید و در پایان یکی را بصورت رندوم انتخاب کنید. اما یک راه دیگر انتخاب دو به دو است فرض کنید 3 تا v یکسان داریم. اول بین v1 , v2 یکی را رندوم انتخاب می کنیم بعد بین v3 و نتیجه قبلی یکی را بصورت رندوم انتخاب می کنیم. (فقط اینکه در روش دوم احتمال 3 اومدن 50 درصد و احتمال 1 اومدن 25 درصد و احتمال 2 اومدن نیز 25 درصد است بنابراین اگر رندوم بودن با احتمال برابر مهم است بهتر است از همان روش اول استفاده کنید (فعلا می توانید از این قسمت گذر کنید و از همین روش ساده که گفتم استفاده کنید.))

Salazar.mi
پنج شنبه 09 آبان 1398, 11:06 صبح
در پایین همان قسمت توضیح دادم: با توجه به اینکه در هر مرحله یک v ساخته می شود برای اینکه بین چند تا یکی را رندوم انتخاب کنیم تا زمانی که همه ساخته نشده اند نمیتوان رندوم انتخاب کرد پس باید همه را در یک آرایه ذخیره کنید و در پایان یکی را بصورت رندوم انتخاب کنید. اما یک راه دیگر انتخاب دو به دو است فرض کنید 3 تا v یکسان داریم. اول بین v1 , v2 یکی را رندوم انتخاب می کنیم بعد بین v3 و نتیجه قبلی یکی را بصورت رندوم انتخاب می کنیم. (فقط اینکه در روش دوم احتمال 3 اومدن 50 درصد و احتمال 1 اومدن 25 درصد و احتمال 2 اومدن نیز 25 درصد است بنابراین اگر رندوم بودن با احتمال برابر مهم است بهتر است از همان روش اول استفاده کنید (فعلا می توانید از این قسمت گذر کنید و از همین روش ساده که گفتم استفاده کنید.))
بله حق با شماست

ولی میخواستم دوباره بپرسم تا مطمین بشم ببخشید شرمنده
بی نهایت ازتون ممنونم کدی که نوشتین را اجرا کردم کاملا درست کار میکنه
فقط باید به جای عدد 1 عدد 2 بزاریم
چون اعداد 2(ممهره قرمز) خونه سطر بعد و ستون بعد دارن که مشکل از کد اولی بود که خودم نوشتم
فقط یه چیزی وقتی دایم f5 میزنم و مقادیر آرایه move به صورت رندوم عوض میشه بین همه حالت ها یه حالتی انتخاب میشه که آرایه move خالی میشه و آرایه a تغییر نمیکند
در واقع هیچ حرکتی نمیتونه انجام بده
چطوری میتونیم بگیم حتما یه حرکتی انجام بده
ممنون میشم جواب بدین
خودم اینو امتحان کردم ولی باز هم احتمال داره آرایه move خالی باشه


$move = [$i, $j, $i+1, $j+1];
if(empty($move))
{
$move = [$i, $j, $i+1, $j+1];
}

ali_sed
پنج شنبه 09 آبان 1398, 12:00 عصر
برای دیباگ بهتره داخل حلقه به ازای هر خانه از بورد اطلاعات مهم را در یک خط نمایش دهید و بررسی کنید مشکل از کجاست.
ممکنه به این علت باشه که هیچ vj ای بزرگتر از v پیدا نکرده باشه که به نحوه محاسبه vj برمیگردد. در هر صورت دیباگ کنید.

Salazar.mi
پنج شنبه 09 آبان 1398, 12:02 عصر
یه سوال دیگه شرمنده
ولی آیا امکان داره در php بگیم همه اعداد را به صورت float در نظر بگیر
یا باید برای هر کدوم جدا بگیم


$w0=-10;
$fw0=floatval($w0);
$w1=50;
$fw1=floatval($w1);
$w2=-30;
$fw2=floatval($w2);
$v=$fw0+($fw1*$blue)+($fw2*$red);
$fv=floatval($v);

Salazar.mi
پنج شنبه 09 آبان 1398, 12:04 عصر
برای دیباگ بهتره داخل حلقه به ازای هر خانه از بورد اطلاعات مهم را در یک خط نمایش دهید و بررسی کنید مشکل از کجاست.
ممکنه به این علت باشه که هیچ vj ای بزرگتر از v پیدا نکرده باشه که به نحوه محاسبه vj برمیگردد. در هر صورت دیباگ کنید.
میخواستم این پست را پاک کنم نشد مشکلمو پایین نوشتم

Salazar.mi
پنج شنبه 09 آبان 1398, 14:22 عصر
اینجا میخوام بگم
بیا تو حالت اول بین همه اون هایی که این شرایط را دارن


$data===2 && $db===1 && $dbb===0

کوچکترین را انتخاب کن بزار $vj1
بعد متغیر های w را طبق مقدار vj1 به روز کن که برای اینکار نیاز داریم که vj1 را از v اولیه کم کنیم ولی متغیر v را تغییر نباید تغییر بدیم
بعدش بین اونایی که این شرایط را دارند


$data===2 && $db===0

کوچکترین را انتخاب کن بزار $vj2
بعد متغیر های w را طبق مقدار vj2 به روز کن که برای اینکار نیاز داریم که vj2 را از v اولیه کم کنیم ولی متغیر v را تغییر نباید تغییر بدیم
بعد بین این $vj1 و $vj2 هر کدام کوچکتر بود حرکت مربوط به اونو انجام بده
از متغیر global هم استفاده کردم ولی نشد
$vj1 را با $vj2 برابر میدونه در واقع نیست $vj1 باید کمتر باشه
تو آرایه a هم هیچ تغییری ایجاد نمیکند

چرا نمیدونم؟؟؟؟؟؟؟؟؟؟؟؟؟؟؟؟؟؟ ؟؟؟؟؟؟






<?php
$a = [
[0,2,0,2,0,2,0,2],
[2,0,2,0,2,0,2,0],
[0,2,0,2,0,2,0,2],
[0,0,1,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[1,0,1,0,1,0,1,0],
[0,1,0,1,0,1,0,1],
[1,0,1,0,1,0,1,0],
];

$red = $blue = 0;
array_walk_recursive($a, function($t) use(&$red, &$blue)
{
if($t==1) {++$blue;}
elseif($t==2) {++$red;}
});
global $w0j1;
global $w1j1;
global $w2j1;
global $w0j2;
global $w1j2;
global $w2j2;
global $vj1;
global $vj2;
global $w0;
global $w1;
global $w2;
$w0=-10;
$w1=50;
$w2=-30;
global $v;
$v=$w0+($w1*$blue)+($w2*$red);
global $vj1;
global $vj2;
$move = [];
$move1 = [];
$move2 = [];

foreach($a as $i=>$row){
foreach($row as $j=>$data){
if(isset($a[$i+1][$j+1]))
{
$db=$a[$i+1][$j+1];
}
if(isset($a[$i+2][$j+2]))
{
$dbb=$a[$i+2][$j+2];
}
if($data===2 && $db===1 && $dbb===0){
if(isset($a[$i+2][$j+2]))
{
//چون نباید بورد اصلی تغییر کند و این حرکت تنها جهت محاسبه وی است بورد را در یک متغییر موقت میریزیم
$tmp1 = $a;
$tmp1[$i+2][$j+2]=2;
$tmp1[$i+1][$j+1]=0;
$tmp1[$i][$j]=0;


//توجه کنید که در هر حرکت ممکن است تعداد مهره ها تغییر کنید پس باید دوباره شمرده شود
$red = $blue = 0;
array_walk_recursive($tmp1, function($t) use(&$red, &$blue)
{
if($t==1) {++$blue;}
elseif($t==2) {++$red;}

});

$vj1=$w0+($w1*$blue)+($w2*$red);
if($vj1 < $v || ($vj1 == $v && rand(0,1)))
{
$error=$vj1-$v;
$w0j1=$w0+0.1*1*$error;
$w1j1=$w1+0.1*$blue*$error;
$w2j1=$w2+0.1*$red*$error;
//ذخیره اطلاعات مربوط به حرکت تا بعدا روی بورد اصلی این حرکت پیاده شود
$move1 = [$i, $j, $i+1, $j+1,$i+2,$j+2];

}

}


}



if($data===2 && $db===0){
if(isset($a[$i+1][$j+1]))
{
//چون نباید بورد اصلی تغییر کند و این حرکت تنها جهت محاسبه وی است بورد را در یک متغییر موقت میریزیم
$tmp2 = $a;
$tmp2[$i+1][$j+1]=2;
$tmp2[$i][$j]=0;


//توجه کنید که در هر حرکت ممکن است تعداد مهره ها تغییر کنید پس باید دوباره شمرده شود
$red = $blue = 0;
array_walk_recursive($tmp2, function($t) use(&$red, &$blue)
{
if($t==1) {++$blue;}
elseif($t==2) {++$red;}
});

$vj2=$w0+($w1*$blue)+($w2*$red);
if($vj2 < $v || ($vj2 == $v && rand(0,1)))
{
$error=$vj2-$v;
$w0j2=$w0+0.1*1*$error;
$w1j2=$w1+0.1*$blue*$error;
$w2j2=$w2+0.1*$red*$error;
//ذخیره اطلاعات مربوط به حرکت تا بعدا روی بورد اصلی این حرکت پیاده شود
$move2 = [$i, $j, $i+1, $j+1];
}

}

}

//انتخاب j1
if($vj1<$vj2 || $vj2===null)
{
if($move1)
{
$v=$w0j1+($w1j1*$blue)+($w2j1*$red);
// جای دو خانه را با هم عضو کن خانه وسط را صفر کن
$tmp1 = $a[$move1[0]][$move1[1]];
$a[$move1[0]][$move1[1]] = $a[$move1[4]][$move1[5]];
$a[$move1[2]][$move1[3]] = 0;
$a[$move1[4]][$move1[5]] = $tmp1;


unset($tmp1);
}
}

//انتخاب j2
elseif($vj2<$vj1 || $vj1===null)
{
if($move2)
{
$v=$w0j2+($w1j2*$blue)+($w2j2*$red);
//جای دو خانه را با هم عضو کن
$tmp2 = $a[$move2[0]][$move2[1]];
$a[$move2[0]][$move2[1]] = $a[$move2[2]][$move2[3]];
$a[$move2[2]][$move2[3]] = $tmp2;


unset($tmp2);

}
}



}

}

var_dump($v);
var_dump($vj1);
var_dump($vj2);
var_dump($move2);
var_dump($move1);


var_dump($a);


?>






ممنون میشم کمکم کنید