منبع اصلی نوشتار زیر در این لینک قرار دارد

حل معمای هشت (puzzle 8) با روش Back tracking

8puzzle2 حل معمای هشت (puzzle 8) با روش Back tracking

بازی معمای هشت ( ۸-puzzle ) یکی از بازی های فکری است که احتمالا در دوران بچگی همه ی ما با آن خود را سرگرم می کردیم.

در شکل زیر بازی معمای هشت را می بینید:8puzzle حل معمای هشت (puzzle 8) با روش Back tracking

همین طور که می بینید ما یک صفحه ی ۳ در ۳ داریم که با ۸ کاشی با شماره های یک تا هشت پر شده اند. در این بازی شما می توانید کاشی های مجاور خانه ی خالی را هول دهید و به جای خانه ی خالی بیاورید مثالا فرض کنید کاشی شماره ی شش را به پایین هول دهیم. شکل زیر ظاهر می شود:8puzzle1 حل معمای هشت (puzzle 8) با روش Back tracking

با این کار ما می توانیم جای کاشی ها رو عوض کنیم.

هدف از این بازی این است که کاشی ها را با جابه جایی به شکل زیر برسانیم و مسیری را که منتهی به جواب می شود را بدست بیاوریم:8puz حل معمای هشت (puzzle 8) با روش Back tracking

ما این سوال را با استفاده از روش عقبگرد ( Back Tracking) که نوعی روش جست و جو است حل می کنیم.

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

فرض کنید به ما این پازل را داده اند حل کنیم:

8 puzzle eight حل معمای هشت (puzzle 8) با روش Back tracking

ما اینجا در این وضعیت سه کار می توانیم بکنیم:

یک :

شش را به پایین حل بدهیم :

8 puzzle eight1 حل معمای هشت (puzzle 8) با روش Back tracking

دو:

یا ۵ را به چپ حل بدهیم:

8 puzzle eight2 حل معمای هشت (puzzle 8) با روش Back tracking

سه :

یا هفت را به راست هول بدهیم:

8 puzzle eight3 حل معمای هشت (puzzle 8) با روش Back tracking

خوب الان تمام سه حالت ممکن را برای آن حالت تولید کردیم.حالا فرض کنید که برای این سه حالت جدید به دست آمده تمام حالتاشونو تولید کنیم ، درخت زیر به دست می آید که به آن گراف حالات می گویند.(با کلیک روی آن آن را در اندازه ی واقعی ببینید)

Tree 8 puzzle حل معمای هشت (puzzle 8) با روش Back tracking

 

حالا ما با جست و جوی درخت بالا می توانیم به جواب برسیم

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

در شکل بالا گره ها شماره گذاری شده است ، جست و جو به روش عقبگرد در دخت بالا به شکل زیر است:

۱ ,۲ ,۵,۱۰,۲۰

به ته درخت رسیدیم آن قدر بالا می رویم تا به نودی برسیم که بتوانیم از آن پایین بیاییم که اگر از مسیری که آمده ایم به عقب برگردیم اولین     نودی که می توانیم از آن پایین برویم گره ی ۵   است که اگر از آن پایین برویم به مسیر زیر به دست می آید:

۱,۲,۵,۱۱,۲۱

به جواب نرسیدیم دوباره کار قبل را تکرار می کنیم تا به جواب برسیم مسیر های زیر مسیرهایی است که تارسیدن به جواب تولید می شود

۱,۲,۵,۱۱,۲۲

۱,۲,۵,۱۱,۲۳

۱,۳,۶,۱۲,۲۴

۱,۳,۶,۱۳,۲۵

۱,۳,۷,۱۴,۲۶,۲۷

مسیر (۱,۳,۷,۱۴,۲۶,۲۷) به حل سوال منتهی می شود پس به جواب رسیده ایم و جست و جوی درخت را متوقف می کنیم.مسیر به دست آمده با خط پر رنگ در شکل مشخص شده است.

آیا قبل از حل مساله باید درخت حالات را تولید کرد و بعد در آن جست و جو کنیم؟

خیر ، اگر بخواهیم کل درخت را بسازیم و بعد در آن جست و جو کنیم حافظه خیلی زیادی را باید مصرف کنیم ، بهمین خاطر در حین حل مسیله درخت را می سازیم.

شاید یک سوال برای شما پیش آمده باشد و آن این است که چرا ما درخت حالت را تا عمق خاصی ساخته ایم در حالی که تا بی نهایت ممکن است عمق درخ ادامه داشته باشد؟

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

 

حالا بریم سراغ کد برنامه :

تابع مقایسه ی دو آرایه ی دو بعدی :

a و b دو آرایه ای هستند که قرار است مقایسه شوند و به صورت اشاره گر به تابع فرستاده شده اند.

n هم طول و عرض آرایه است.

خروجی به صورت bool است که یا مقدار True را دارد یا False.

bool compareToArray(int **a, int **b, int n)
{
	bool equality = true;
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < n; j++)
		{
			if (a[i][j] != b[i][j])
			{
				equality = false;
			}
		}
	}
	return equality;
}

 تابع حل سوال n puzzle :

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

این تابع به صورت بازگشتی است.

int **current_status : آرایه ی دو بعدی است که حالتی از پازل است که باید آن را حل کنیم

int **goal_status : آرایه ای دو بعدی است که هدف بازی است و باید به آن برسیم

در آریه ی  پازل خانه ی خالی را با صفر نمایش می دهیم.

vector <int> *path :  وکتوری از جنس اعداد صحیح است که مسیری را طی کرده ایم در آن قرار دارد که اعداد در آن به شرح زیر است:

۰: یعنی خانه ی خالی در پازل را به سمت بالا برده ایم

۱: یعنی خانه ی خالی در پازل را به سمت چپ برده ایم

۲: یعنی خانه ی خالی در پازل را به سمت پایین  برده ایم

۳: یعنی خانه ی خالی در پازل را به سمت راست برده ایم

int deep: حداکثر عمق درختی است که ما می توانیم به در درخت پیش برویم. اولین بار هنگام فراخوانی به deep مقدار ۱- را می دهیم.

int i_zeroPoint : مختصات i کاشی خالی است.

int j_zeroPoint : مختصات j کاشی خالی است.

int lastMove: حرکت قبلیمان در آن است تا دوباره آن را تکرار نکنیم و به مرحله ی قبل برویم. چون اگر به مرحله قبل برویم ممکن است توی حلقه ی هایی بی افتیم که مدت حل سوال را زیاد می کند. البته از vector <int> *path هم می توانستیم جای  lastMove استفاده کنیم!

 

این تابع بازگشتی است و درخت را در خودش می سازد.

تابع حل مسیله ی puzzle , Gem Puzzle, Boss Puzzle, Game of Fifteen, Mystic Square  , هشت پازل  ,  شانزده پازل , پازل , n پازل ، معمای هشت

bool eightPuzzle(int **current_status, int **goal_status, vector <int> *path, int n, int deep, int i_zeroPoint, int j_zeroPoint, int lastMove)
{
	if (compareToArray(current_status, goal_status, n))
	{
		return true;
	}
	if (deep > 20)
	{
		path->pop_back();
		return false;
	}

	for (int i = 0; i < 4; i++)
	{
		if ((lastMove == 0 && i == 2) || (lastMove == 2 && i == 0))
		{
			continue;
		}
		if ((lastMove == 1 && i == 3) || (lastMove == 3 && i == 1))
		{
			continue;
		}

		switch (i)
		{
		case 0:
		{
				  //Up
				  if (i_zeroPoint - 1 >= 0 )
				  {
					  current_status[i_zeroPoint][j_zeroPoint] = current_status[i_zeroPoint - 1][j_zeroPoint];
					  current_status[i_zeroPoint - 1][j_zeroPoint] = 0;
					  path->push_back(i);
					  if (eightPuzzle(current_status, goal_status, path, n, deep + 1, i_zeroPoint - 1, j_zeroPoint, i))
					  {
						  current_status[i_zeroPoint - 1][j_zeroPoint] = current_status[i_zeroPoint][j_zeroPoint];
						  current_status[i_zeroPoint][j_zeroPoint] = 0;
						  return true;
					  }
					  current_status[i_zeroPoint - 1][j_zeroPoint] = current_status[i_zeroPoint][j_zeroPoint];
					  current_status[i_zeroPoint][j_zeroPoint] = 0;
				  }
				  break;
		}
		case 1:
		{
				  //Left
				  if (j_zeroPoint - 1 >= 0)
				  {
					  current_status[i_zeroPoint][j_zeroPoint] = current_status[i_zeroPoint][j_zeroPoint - 1];
					  current_status[i_zeroPoint][j_zeroPoint - 1] = 0;
					  path->push_back(i);
					  if (eightPuzzle(current_status, goal_status, path, n, deep + 1, i_zeroPoint, j_zeroPoint - 1, i))
					  {
						  current_status[i_zeroPoint][j_zeroPoint - 1] = current_status[i_zeroPoint][j_zeroPoint];
						  current_status[i_zeroPoint][j_zeroPoint] = 0;
						  return true;
					  }
					  current_status[i_zeroPoint][j_zeroPoint - 1] = current_status[i_zeroPoint][j_zeroPoint];
					  current_status[i_zeroPoint][j_zeroPoint] = 0;
				  }
				  break;
		}
		case 2:
		{
				  //Down
				  if (i_zeroPoint + 1 < n)
				  {
					  current_status[i_zeroPoint][j_zeroPoint] = current_status[i_zeroPoint + 1][j_zeroPoint];
					  current_status[i_zeroPoint + 1][j_zeroPoint] = 0;
					  path->push_back(i);
					  if (eightPuzzle(current_status, goal_status, path, n, deep + 1, i_zeroPoint + 1, j_zeroPoint, i))
					  {
						  current_status[i_zeroPoint + 1][j_zeroPoint] = current_status[i_zeroPoint][j_zeroPoint];
						  current_status[i_zeroPoint][j_zeroPoint] = 0;
						  return true;
					  }
					  current_status[i_zeroPoint + 1][j_zeroPoint] = current_status[i_zeroPoint][j_zeroPoint];
					  current_status[i_zeroPoint][j_zeroPoint] = 0;
				  }
				  break;
		}
		case 3:
		{
				  //Right
				  if (j_zeroPoint + 1 < n)
				  {
					  current_status[i_zeroPoint][j_zeroPoint] = current_status[i_zeroPoint][j_zeroPoint + 1];
					  current_status[i_zeroPoint][j_zeroPoint + 1] = 0;
					  path->push_back(i);
					  if (eightPuzzle(current_status, goal_status, path, n, deep + 1, i_zeroPoint, j_zeroPoint + 1, i))
					  {
						  current_status[i_zeroPoint][j_zeroPoint + 1] = current_status[i_zeroPoint][j_zeroPoint];
						  current_status[i_zeroPoint][j_zeroPoint] = 0;
						  return true;
					  }
					  current_status[i_zeroPoint][j_zeroPoint + 1] = current_status[i_zeroPoint][j_zeroPoint];
					  current_status[i_zeroPoint][j_zeroPoint] = 0;
				  }
				  break;
		}
		
		default:
			break;
		}
	}
	path->pop_back();
	return false;
}

تابع showPath :

این تابع حرکاتی را که باید روی خانه ی خالی انجام دهیم را که در وکتور  vector <int>* path قرار دارد روی حالت اولیه انجام می دهد و قدم به قدم پازل حل شده را نمایش می دهد.

void showPath(int **current_status, int **goal_status, vector <int> *path, int n,int i_zeroPoint, int j_zeroPoint)
{
	int lasti;
	int lastj;

	std::cout << "goal state:" << endl;
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < n; j++)
		{
			if (goal_status[i][j] == 0)
			{
				std::cout << " " << " ";
				continue;
			}
			std::cout << goal_status[i][j] << " ";
		}
		std::cout << endl;
	}
	std::cout << endl;

	std::cout << "start state:" << endl;
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < n; j++)
		{
			if (current_status[i][j] == 0)
			{
				std::cout << " " << " ";
				continue;
			}
			std::cout << current_status[i][j] << " ";
		}
		std::cout << endl;
	}
	std::cout << endl;
	

	int **temp = new int*[3];
	for (int i = 0; i < 3; i++)
	{
		temp[i] = new int[3];
	}


	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < n; j++)
		{
			temp[i][j] = current_status[i][j];
			if (temp[i][j] == 0)
			{
				lasti = i;
				lastj = j;
			}
		}
	}

	std::cout << "Number of total Step " << path->size() << "." << endl << endl;
	for (int i = 0; i < path->size(); i++)
	{
		std::cout << "Step " << i + 1 << ":"<< endl;
		switch (path->at(i))
		{
		case 0:
		{
				  temp[lasti][lastj] = temp[lasti - 1][lastj];
				  temp[lasti - 1][lastj] = 0;
				  lasti = lasti - 1;
				  break;
		}
		case 1:
		{
				  temp[lasti][lastj] = temp[lasti][lastj - 1];
				  temp[lasti][lastj - 1] = 0;
				  lastj = lastj - 1;
				  break;
		}
		case 2:
		{
				  temp[lasti][lastj] = temp[lasti + 1][lastj];
				  temp[lasti + 1][lastj] = 0;
				  lasti = lasti + 1;
				  break;
		}
		case 3:
		{
				  temp[lasti][lastj] = temp[lasti][lastj + 1];
				  temp[lasti][lastj + 1] = 0;
				  lastj = lastj + 1;
				  break;
		}
		default:
			break;
		}
		//
		for (int p = 0; p < n; p++)
		{
			for (int q = 0; q < n; q++)
			{
				if (temp[p][q] == 0)
				{
					std::cout << " " << " ";
					continue;
				}
				std::cout << temp[p][q] << " ";
			}
			std::cout << endl;
		}
		std::cout << endl;
		//
	}
	std::cout << endl;
}

 

 

در زیر کد کلی برنامه  هشت پازل (معمای هشت) را با سی پلاس پلاس می بینید که در Main آن یک مثال به به تابع فرستاده شده:

(قبل از نوشتن کد یک عکس از خروجی را قرار داده ام)

output of 8puzzle حل معمای هشت (puzzle 8) با روش Back tracking

 

// 8-puzzle-back tracking.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <iostream>
#include <vector>

using namespace std;

bool compareToArray(int **a, int **b, int n)
{
	bool equality = true;
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < n; j++)
		{
			if (a[i][j] != b[i][j])
			{
				equality = false;
			}
		}
	}
	return equality;
}

bool eightPuzzle(int **current_status, int **goal_status, vector <int> *path, int n, int deep, int i_zeroPoint, int j_zeroPoint, int lastMove)
{
	if (compareToArray(current_status, goal_status, n))
	{
		return true;
	}
	if (deep > 20)
	{
		path->pop_back();
		return false;
	}

	for (int i = 0; i < 4; i++)
	{
		if ((lastMove == 0 && i == 2) || (lastMove == 2 && i == 0))
		{
			continue;
		}
		if ((lastMove == 1 && i == 3) || (lastMove == 3 && i == 1))
		{
			continue;
		}

		switch (i)
		{
		case 0:
		{
				  //Up
				  if (i_zeroPoint - 1 >= 0 )
				  {
					  current_status[i_zeroPoint][j_zeroPoint] = current_status[i_zeroPoint - 1][j_zeroPoint];
					  current_status[i_zeroPoint - 1][j_zeroPoint] = 0;
					  path->push_back(i);
					  if (eightPuzzle(current_status, goal_status, path, n, deep + 1, i_zeroPoint - 1, j_zeroPoint, i))
					  {
						  current_status[i_zeroPoint - 1][j_zeroPoint] = current_status[i_zeroPoint][j_zeroPoint];
						  current_status[i_zeroPoint][j_zeroPoint] = 0;
						  return true;
					  }
					  current_status[i_zeroPoint - 1][j_zeroPoint] = current_status[i_zeroPoint][j_zeroPoint];
					  current_status[i_zeroPoint][j_zeroPoint] = 0;
				  }
				  break;
		}
		case 1:
		{
				  //Left
				  if (j_zeroPoint - 1 >= 0)
				  {
					  current_status[i_zeroPoint][j_zeroPoint] = current_status[i_zeroPoint][j_zeroPoint - 1];
					  current_status[i_zeroPoint][j_zeroPoint - 1] = 0;
					  path->push_back(i);
					  if (eightPuzzle(current_status, goal_status, path, n, deep + 1, i_zeroPoint, j_zeroPoint - 1, i))
					  {
						  current_status[i_zeroPoint][j_zeroPoint - 1] = current_status[i_zeroPoint][j_zeroPoint];
						  current_status[i_zeroPoint][j_zeroPoint] = 0;
						  return true;
					  }
					  current_status[i_zeroPoint][j_zeroPoint - 1] = current_status[i_zeroPoint][j_zeroPoint];
					  current_status[i_zeroPoint][j_zeroPoint] = 0;
				  }
				  break;
		}
		case 2:
		{
				  //Down
				  if (i_zeroPoint + 1 < n)
				  {
					  current_status[i_zeroPoint][j_zeroPoint] = current_status[i_zeroPoint + 1][j_zeroPoint];
					  current_status[i_zeroPoint + 1][j_zeroPoint] = 0;
					  path->push_back(i);
					  if (eightPuzzle(current_status, goal_status, path, n, deep + 1, i_zeroPoint + 1, j_zeroPoint, i))
					  {
						  current_status[i_zeroPoint + 1][j_zeroPoint] = current_status[i_zeroPoint][j_zeroPoint];
						  current_status[i_zeroPoint][j_zeroPoint] = 0;
						  return true;
					  }
					  current_status[i_zeroPoint + 1][j_zeroPoint] = current_status[i_zeroPoint][j_zeroPoint];
					  current_status[i_zeroPoint][j_zeroPoint] = 0;
				  }
				  break;
		}
		case 3:
		{
				  //Right
				  if (j_zeroPoint + 1 < n)
				  {
					  current_status[i_zeroPoint][j_zeroPoint] = current_status[i_zeroPoint][j_zeroPoint + 1];
					  current_status[i_zeroPoint][j_zeroPoint + 1] = 0;
					  path->push_back(i);
					  if (eightPuzzle(current_status, goal_status, path, n, deep + 1, i_zeroPoint, j_zeroPoint + 1, i))
					  {
						  current_status[i_zeroPoint][j_zeroPoint + 1] = current_status[i_zeroPoint][j_zeroPoint];
						  current_status[i_zeroPoint][j_zeroPoint] = 0;
						  return true;
					  }
					  current_status[i_zeroPoint][j_zeroPoint + 1] = current_status[i_zeroPoint][j_zeroPoint];
					  current_status[i_zeroPoint][j_zeroPoint] = 0;
				  }
				  break;
		}
		
		default:
			break;
		}
	}
	path->pop_back();
	return false;
}

void showPath(int **current_status, int **goal_status, vector <int> *path, int n,int i_zeroPoint, int j_zeroPoint)
{
	int lasti;
	int lastj;

	std::cout << "goal state:" << endl;
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < n; j++)
		{
			if (goal_status[i][j] == 0)
			{
				std::cout << " " << " ";
				continue;
			}
			std::cout << goal_status[i][j] << " ";
		}
		std::cout << endl;
	}
	std::cout << endl;

	std::cout << "start state:" << endl;
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < n; j++)
		{
			if (current_status[i][j] == 0)
			{
				std::cout << " " << " ";
				continue;
			}
			std::cout << current_status[i][j] << " ";
		}
		std::cout << endl;
	}
	std::cout << endl;
	

	int **temp = new int*[3];
	for (int i = 0; i < 3; i++)
	{
		temp[i] = new int[3];
	}


	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < n; j++)
		{
			temp[i][j] = current_status[i][j];
			if (temp[i][j] == 0)
			{
				lasti = i;
				lastj = j;
			}
		}
	}

	std::cout << "Number of total Step " << path->size() << "." << endl << endl;
	for (int i = 0; i < path->size(); i++)
	{
		std::cout << "Step " << i + 1 << ":"<< endl;
		switch (path->at(i))
		{
		case 0:
		{
				  temp[lasti][lastj] = temp[lasti - 1][lastj];
				  temp[lasti - 1][lastj] = 0;
				  lasti = lasti - 1;
				  break;
		}
		case 1:
		{
				  temp[lasti][lastj] = temp[lasti][lastj - 1];
				  temp[lasti][lastj - 1] = 0;
				  lastj = lastj - 1;
				  break;
		}
		case 2:
		{
				  temp[lasti][lastj] = temp[lasti + 1][lastj];
				  temp[lasti + 1][lastj] = 0;
				  lasti = lasti + 1;
				  break;
		}
		case 3:
		{
				  temp[lasti][lastj] = temp[lasti][lastj + 1];
				  temp[lasti][lastj + 1] = 0;
				  lastj = lastj + 1;
				  break;
		}
		default:
			break;
		}
		//
		for (int p = 0; p < n; p++)
		{
			for (int q = 0; q < n; q++)
			{
				if (temp[p][q] == 0)
				{
					std::cout << " " << " ";
					continue;
				}
				std::cout << temp[p][q] << " ";
			}
			std::cout << endl;
		}
		std::cout << endl;
		//open-mind.ir
	}
	std::cout << endl;
}

int main()
{
	vector<int> *path = new vector<int>;

	int **current_status = new int*[3];
	for (int i = 0; i < 3; i++)
	{
		current_status[i] = new int[3];
	}
	int **goal_status = new int*[3];
	for (int i = 0; i < 3; i++)
	{
		goal_status[i] = new int[3];
	}

	current_status[0][0] = 2;
	current_status[0][1] = 8;
	current_status[0][2] = 3;
	current_status[1][0] = 1;
	current_status[1][1] = 6;
	current_status[1][2] = 4;
	current_status[2][0] = 7;
	current_status[2][1] = 0;
	current_status[2][2] = 5;

	goal_status[0][0] = 1;
	goal_status[0][1] = 2;
	goal_status[0][2] = 3;
	goal_status[1][0] = 8;
	goal_status[1][1] = 0;
	goal_status[1][2] = 4;
	goal_status[2][0] = 7;
	goal_status[2][1] = 6;
	goal_status[2][2] = 5;

	eightPuzzle(current_status, goal_status, path, 3,0, 2, 1,-1);

	showPath(current_status, goal_status, path, 3, 2,1);

	return 0;
}

 

digg حل معمای هشت (puzzle 8) با روش Back tracking  reddit حل معمای هشت (puzzle 8) با روش Back tracking  stumbleupon حل معمای هشت (puzzle 8) با روش Back tracking  yahoo buzz حل معمای هشت (puzzle 8) با روش Back tracking  dzone حل معمای هشت (puzzle 8) با روش Back tracking  facebook حل معمای هشت (puzzle 8) با روش Back tracking  delicious حل معمای هشت (puzzle 8) با روش Back tracking  dotnetkicks حل معمای هشت (puzzle 8) با روش Back tracking  dotnetshoutout حل معمای هشت (puzzle 8) با روش Back tracking  linkedin حل معمای هشت (puzzle 8) با روش Back tracking  technorati حل معمای هشت (puzzle 8) با روش Back tracking  twitter حل معمای هشت (puzzle 8) با روش Back tracking  google buzz حل معمای هشت (puzzle 8) با روش Back tracking  



برچسب ها : , , ,

به سیاره لینوکس امتیاز دهید

به اين صفحه امتياز دهيد