0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Df-Pnアルゴリズムでチェス・プロブレムを解いてみた。

Posted at

スクリーンショット 2025-05-04 153506.png
スクリーンショット 2025-05-04 153525.png

		const int INFINITYVAL = 320000; // 無限大
		const int HASH_SIZE = 1024 * 1024;

		const int SUCCESS = 1;
		const int UN_FINISHED = 0;
		const int FAILURE = -1;

		Play[] answer = new Play[32];

		ulong hash(ulong Key)
		{
			return Key % (HASH_SIZE);
		}
		int MinFunc(int a, int b)
		{
			if (a < b) return a;
			return b;
		}
		int addition(int n, int m)
		{
			if (n == INFINITYVAL || m == INFINITYVAL)
				return INFINITYVAL;
			else
				return n + m;

		}
		// 子ノードで最小の証明数を求める
		int MinPn(List<Play> children)
		{
			int pn = 0, dn = 0;
			int pn_min = INFINITYVAL;
			for (int i = 0; i < children.Count; i++)
			{
				TTLookUp(children[i].HashKey, ref pn, ref dn);
				pn_min = pn_min < pn ? pn_min : pn;
			}
			return pn_min;
		}
		// 子ノードで最小の証明数の和を計算
		int SumPn(List<Play> children)
		{
			int pn = 0, dn = 0;
			int pn_sum = 0;
			for (int i = 0; i < children.Count; i++)
			{
				TTLookUp(children[i].HashKey, ref pn, ref dn);
				pn_sum = addition(pn_sum, pn);
			}
			return pn_sum;
		}
		// 子ノードで最小の反証数を求める
		int MinDn(List<Play> children)
		{
			int pn = 0, dn = 0;
			int dn_min = INFINITYVAL;
			for (int i = 0; i < children.Count; i++)
			{
				TTLookUp(children[i].HashKey, ref pn, ref dn);
				dn_min = dn_min < dn ? dn_min : dn;
			}
			return dn_min;

		}
		// 子ノードで最小の反証数の和を計算
		int SumDn(List<Play> children)
		{
			int pn = 0, dn = 0;
			int dn_sum = 0;
			for (int i = 0; i < children.Count; i++)
			{
				TTLookUp(children[i].HashKey, ref pn, ref dn);
				dn_sum = addition(dn_sum, dn);
			}
			return dn_sum;

		}
		int SelectChild_OR(List<Play> children, ref int dnc, ref int pn2)
		{
			int n = -1;
			int pc;
			int p_num = 0, d_num = 0;
			dnc = pc = pn2 = INFINITYVAL;
			for (int i = 0; i < children.Count; i++)
			{
				TTLookUp(children[i].HashKey, ref p_num, ref d_num);
				// pc  ɍŏ    p_num      
				// pn2  ɓ Ԗڂɏ      p_num       
				if (p_num < pc)
				{
					n = i;
					pn2 = pc;
					pc = p_num;
					dnc = d_num;
				}
				else if (p_num < pn2)
				{
					pn2 = p_num;
				}
			}
			return n;

		}
		int SelectChild_AND(List<Play> children, ref int pnc, ref int dn2)
		{
			int n = -1;
			int dc;
			int p_num = 0, d_num = 0;
			pnc = dc = dn2 = INFINITYVAL;
			for (int i = 0; i < children.Count; i++)
			{
				TTLookUp(children[i].HashKey, ref p_num, ref d_num);
				// dc  ɍŏ    d_num      
				// dn2  ɓ Ԗڂɏ      d_num       
				if (d_num < dc)
				{
					n = i;
					dn2 = dc;
					pnc = p_num;
					dc = d_num;
				}
				else if (d_num < dn2)
				{
					dn2 = d_num;
				}
			}
			return n;

		}
		void TTSave(ulong Key, int p_num, int d_num)
		{
			ulong k;
			k = hash(Key);
			MateTbl[k].HashKey = Key;
			MateTbl[k].pf = p_num;
			MateTbl[k].dn = d_num;

		}
		void TTLookUp(ulong Key, ref int p_num, ref int d_num)
		{
			ulong k;
			k = hash(Key);

			if (MateTbl[k].HashKey == Key)
			{
				p_num = MateTbl[k].pf;
				d_num = MateTbl[k].dn;
			}
			else
			{
				p_num = 1;
				d_num = 1;
			}
		}
	public int DfPnSearch(Board b, int color, int depth, int depthMax)
	{
		int mate = FAILURE - 1;
		int root_th_p_num, root_th_d_num;
		int p_num, d_num;
		for (int i = 0; i < HASH_SIZE; i++)
		{
			MateTbl[i] = new MateEntry();
		}
		root_th_p_num = root_th_d_num = INFINITYVAL - 1;
		p_num = d_num = INFINITYVAL - 1;
		MidOr(b, color, depth, depthMax, ref p_num, ref d_num, ref root_th_p_num, ref root_th_d_num);
		if (p_num == 0) mate = SUCCESS;
		if (d_num == 0) mate = FAILURE;
		return mate;
	}

	void MidOr(Board b, int color, int depth, int depthMax, ref int p_num, ref int d_num, ref int mother_th_p_num, ref int mother_th_d_num)
	{
		int i;
		int child_th_p_num;
		int child_th_d_num;
		int dnc = 0;
		int pn2 = 0;
		
		TTLookUp(b.HashKey, ref p_num, ref d_num);
		if (mother_th_p_num <= p_num || mother_th_d_num <= d_num)
		{
			// 臒l 𒴂    Ƃ 
			mother_th_p_num = p_num;
			mother_th_d_num = d_num;
			return;
		}
		
		List<Play> valid_moves = new List<Play>();
		b.get_valid_moves(color, ref valid_moves);
		if (valid_moves.Count == 0)
		{
				p_num = INFINITYVAL; d_num = 0;
				TTSave(b.HashKey, p_num, d_num);
				valid_moves.Clear();
				return;
		}
        // 千日手の処理
		int perpetual = 0;
		if (depth > 1)
		{
			for (i = depth - 1; i > 0; i -= 2)
			{
				if (b.HashHistory[i] == b.HashKey)
				{
					perpetual++;
				}
			}
		}
		if (perpetual > 1)
		{
			p_num = INFINITYVAL; d_num = 0;
			TTSave(b.HashKey, p_num, d_num);
			return;
		}
		if (depth > depthMax)
		{
			p_num = INFINITYVAL; d_num = 0;
			TTSave(b.HashKey, p_num, d_num);
			valid_moves.Clear();
			return;
		}
		for (int j = 0; j < valid_moves.Count; j++)
		{
			b.make_move(color, valid_moves[j]);
			if (b.controlW[b.kingBpos] != 0) valid_moves[j].value = 1; else valid_moves[j].value = 0;
			valid_moves[j].HashKey = b.HashKey;
			valid_moves[j].PathKey = b.PathSeed[j * depth];
			b.undo_move(color);
		}
		// 指し手を順序付ける
		for (i = 0; i < valid_moves.Count; i++)
		{
			for (int j = i + 1; j < valid_moves.Count; j++)
			{
				if (valid_moves[i].value < valid_moves[j].value)
				{
					Play play = valid_moves[i];
					valid_moves[i] = valid_moves[j];
					valid_moves[j] = play;
				}
			}
		}
		dnc = INFINITYVAL;
		pn2 = INFINITYVAL;
		while (mother_th_p_num > MinPn(valid_moves) && mother_th_d_num > SumDn(valid_moves))
		{
			i = SelectChild_OR(valid_moves, ref dnc, ref pn2);
			// 臒l ̐ݒ 
			child_th_p_num = MinFunc(mother_th_p_num, pn2 + 1);
			child_th_d_num = mother_th_d_num + dnc - SumDn(valid_moves);
			b.make_move(color, valid_moves[i]);//Refresh();MessageBox.Show("");
			MidAnd(b, b.flip(color), depth + 1, depthMax, ref p_num, ref d_num, ref child_th_p_num, ref child_th_d_num);
			b.undo_move(color);
			Best[0, depth] = valid_moves[i];
		}
		p_num = MinPn(valid_moves);
		d_num = SumDn(valid_moves);
		TTSave(b.HashKey, p_num, d_num);
		valid_moves.Clear();
	}
	void MidAnd(Board b, int color, int depth, int depthMax, ref int p_num, ref int d_num, ref int mother_th_p_num, ref int mother_th_d_num)
	{
		int i;
		int child_th_p_num;
		int child_th_d_num;
		int pnc;
		int dn2;
		
		TTLookUp(b.HashKey, ref p_num, ref d_num);
		if (mother_th_p_num <= p_num || mother_th_d_num <= d_num)
		{
			// 臒l 𒴂    Ƃ 
			mother_th_p_num = p_num;
			mother_th_d_num = d_num;
			return;
		}
		List<Play> valid_moves = new List<Play>();
		b.get_valid_moves(color, ref valid_moves);
		if (valid_moves.Count == 0)
		{
            // チェックメイト
			if (b.controlW[b.kingBpos] != 0)
			{
				p_num = 0; d_num = INFINITYVAL;
				TTSave(b.HashKey, p_num, d_num);
				pCount = depth;
				valid_moves.Clear();
				return;
			}
			else//ステイルメイト
			{
				p_num = INFINITYVAL; d_num = 0;
				TTSave(b.HashKey, p_num, d_num);
				valid_moves.Clear();
				return;
			}
		}
        
        // 千日手の処理
		int perpetual = 0;
		if (depth > 1)
		{
			for (i = depth - 1; i > 0; i -= 2)
			{
				if (b.HashHistory[i] == b.HashKey)
				{
					perpetual++;
				}
			}
		}
		if (perpetual > 1)
		{
			p_num = INFINITYVAL; d_num = 0;
			TTSave(b.HashKey, p_num, d_num);
			return;
		}
		
		for (i = 0; i < valid_moves.Count; i++)
		{
			b.make_move(color, valid_moves[i]);
			valid_moves[i].HashKey = b.HashKey;
			b.undo_move(color);
		}
		
		pnc = INFINITYVAL;
		dn2 = INFINITYVAL;
		while (mother_th_d_num > MinDn(valid_moves) && mother_th_p_num > SumPn(valid_moves))
		{
			i = SelectChild_AND(valid_moves, ref pnc, ref dn2);
			// 臒l ̐ݒ 
			child_th_p_num = mother_th_p_num + pnc - SumPn(valid_moves);
			child_th_d_num = MinFunc(mother_th_d_num, dn2 + 1);
			b.make_move(color, valid_moves[i]);
   			MidOr(b, b.flip(color), depth + 1, depthMax, ref p_num, ref d_num, ref child_th_p_num, ref child_th_d_num);
			b.undo_move(color);
			Best[0, depth] = valid_moves[i];
		}
		d_num = MinDn(valid_moves);
		p_num = SumPn(valid_moves);
		TTSave(b.HashKey, p_num, d_num);
		valid_moves.Clear();
	}

 4手詰め(将棋の7手詰め)が一瞬で解けました。
ソースは以下にあるC++をC#に移植したものを使いました。
https://www.cc.kochi-u.ac.jp/~tyamag/jyohou/crosscram.pdf

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?