zerojudge f790. 勝利的五子棋

題目請參考 https://zerojudge.tw/ShowProblem?problemid=f790.

這題要判斷兩種活三,活四和死四再加上有水平,垂直和兩種斜向共四種方向, 還有斜向時的長度有可能是七子,六子或五子, 所以程式寫起來應該頗為複雜. 為了降低程式的複雜度,我設計一個可以適用各種方向的getn( ), 因為四種方向只是座標增減的方法不同而已. 所以如果有了起始點和方向後,第幾子的狀態都可以用下面的函式來取得.每子的先後順序是從左到右,從上到下.

char d[7][8]; //儲存測資的字串

int VH_TYPE;//0:水平, 1:垂直, 2:斜線(左下往右上), 3:倒斜線(左上往右下)
int start_y;
int start_x;
inline char getn(int index){
	switch(VH_TYPE){
		case 0:return d[start_y][start_x+index];
		case 1:return d[start_y+index][start_x];
		case 2:return d[start_y-index][start_x+index];
		case 3:return d[start_y+index][start_x+index];
	}
}
C++

水平和垂直方向都是七子, 只有斜向時可能出現只有六子或五子. 少於五子不存在任何活三,活四和死四,所以不用考慮. 我把七子,六子和五子分三個函式來處理. 只有五子的情形下,只有一種連續的活三和兩種死四.

01234
活三XOOOX
死四OOOOX
死四XOOOO

活三分成連續活三和不連續活三兩種只是為了除錯方便. 五子只有連續活三.

int L31=0;//活三第一種 xooox(全相連)
int L32=0;//活三第二種 xooxox(有斷開)
int L4=0;//活四xoooox
int D4=0;//死四xoooo

//5點斜線方向1種連續活三,2種死四
void Check5(int y, int x, int type){
	start_y=y;
	start_x=x;
	VH_TYPE=type;

	if(getn(2)=='o'){
		if(getn(3)=='o'){
			if(getn(4)=='o'){
				if(getn(1)=='o'){
					if(getn(0)=='x'){
						D4++;
					}
				}

			}else{
				if(getn(1)=='o'){
					if(getn(0)=='o'){
						D4++;
					}
					else{
						L31++;
					}
				}
			}
		}
	}
}
C++

只有五子的斜線只存在以下四種,依序檢查就好.

//檢查5點的斜線
Check5(4,0,2);
Check5(6,2,2);
//檢查5點的反斜線
Check5(0,2,3);
Check5(2,0,3);
C++

再來就是處理六子, 六子有2種連續活三,2種不連續活三,1種活四,2種死四.

012345
連續活三XOOOX
連續活三XOOOX
不連續活三XOXOOX
不連續活三XOOXOX
活四XOOOOX
死四OOOOX
死四XOOOO

以下程式搭配上面表格看就輕鬆了.


void Check6(int y, int x, int type){
	start_y=y;
	start_x=x;
	VH_TYPE=type;
	if(getn(3)=='o'){
		if(getn(4)=='o'){
			if(getn(5)=='o'){
				if(getn(2)=='o'){
					if(getn(1)=='x'){
						D4++;
					}
				}

			}else{
				if(getn(2)=='o'){
					if(getn(1)=='o'){
						if(getn(0)=='x'){
							L4++;
						}
					}else{
						L31++;
					}
				}else{
					if(getn(1)=='o'){
						if(getn(0)=='x'){
							L32++;
						}

					}

				}
			}
		}else{
			if(getn(2)=='o'){
				if(getn(1)=='o'){
					if(getn(0)=='o'){
						D4++;
					}else{
						L31++;
					}
				}
			}
		}

	}else{
		if(getn(4)=='o' && getn(5)=='x'){
			if(getn(2)=='o' && getn(1)=='o'){
				if(getn(0)=='x'){
					L32++;
				}

			}
		}
	}
}
C++

六子的斜線也僅有四條要檢查.

//檢查6點的斜線
Check6(5,0,2);
Check6(6,1,2);
//檢查6點的反斜線
Check6(0,1,3);
Check6(1,0,3);
C++

最後處理七子, 七子有3種連續活三,4種不連續活三,2種活四,2種死四.

0123456
連續活三XOOOX
連續活三XOOOX
連續活三XOOOX
不連續活三XOXOOX
不連續活三XOXOOX
不連續活三XOOXOX
不連續活三XOOXOX
活四XOOOOX
活四XOOOOX
死四OOOOX
死四XOOOO

七子的程式Check7( )有點長,就自己看完整程式吧.

最後處理輸出. 要記得L31+L32才是活三的總數.

void PrintNumber(int n){
	switch(n){
		case 1:break;
		case 2:printf("雙"); break;
		case 3:printf("參"); break;
		case 4:printf("肆"); break;
		case 5:printf("伍"); break;
		case 6:printf("陸"); break;
		case 7:printf("柒"); break;
		case 8:printf("捌"); break;
		case 9:printf("玖"); break;
		default:printf("拾"); break;
	}
}

int main(){
        ...
        if(D4>0){
		PrintNumber(D4);
		printf("死四");
	}
	if(L4>0){
		PrintNumber(L4);
		printf("活四");
	}
	int L3=L31+L32;
	if(L3>0){
		PrintNumber(L3);
		printf("活三");
	}
}	
C++

完整程式如下. AC時間2ms.

#include <iostream>
#include <stdio.h>

using namespace std;

//f790.
char d[7][8]; //儲存測資的字串

int VH_TYPE;//0:水平, 1:垂直, 2:斜線(左下往右上), 3:倒斜線(左上往右下)
int start_y;
int start_x;
inline char getn(int index){
	switch(VH_TYPE){
		case 0:return d[start_y][start_x+index];
		case 1:return d[start_y+index][start_x];
		case 2:return d[start_y-index][start_x+index];
		case 3:return d[start_y+index][start_x+index];
	}
}

int L31=0;//活三第一種 xooox(全相連)
int L32=0;//活三第二種 xooxox(有斷開)
int L4=0;//活四xoooox
int D4=0;//死四xoooo

//7點有3種連續活三,4種不連續活三,2種活四,2種死四
//0123456
//xooox   連續活三
// xooox  連續活三
//  xooox 連續活三
//xoxoox  不連續活三
// xoxoox 不連續活三
//xooxox  不連續活三
// xooxox 不連續活三
//xoooox  活四
// xoooox 活四
//oooox   死四
//  xoooo 死四

void Check7(int y, int x, int type){
	start_y=y;
	start_x=x;
	VH_TYPE=type;
	if(getn(3)=='o'){
		if(getn(4)=='o'){
			if(getn(5)=='o'){
				if(getn(6)=='o'){
					if(getn(2)=='x'){
						D4++;
					}
				}else{
					if(getn(2)=='o'){
						if(getn(1)=='x'){
							L4++;
						}
					}else{
						L31++;
					}
				}
			}else{
				if(getn(2)=='o'){
					if(getn(1)=='o'){
						if(getn(0)=='x'){
							L4++;
						}
					}else{
						L31++;
					}
				}else{
					if(getn(1)=='o'){
						if(getn(0)=='x'){
							L32++;
						}
					}

				}
			}
		}else{
			if(getn(2)=='o'){
				if(getn(1)=='o'){
					if(getn(0)=='o'){
						D4++;
					}else{
						L31++;
					}
				}else{
					if(getn(5)=='o'){
						if(getn(6)=='x'){
							L32++;
						}
					}
				}
			}
		}
	}else{
		if(getn(4)=='o'){
			if(getn(5)=='o'){
				if(getn(6)=='x'){
					if(getn(2)=='o'){
						if(getn(1)=='x'){
							L32++;
						}
					}
				}
			}else{
				if(getn(2)=='o'){
					if(getn(1)=='o'){
						if(getn(0)=='x'){
							L32++;
                        }
					}
				}
			}
		}
	}
}

//6點有2種連續活三,2種不連續活三,1種活四,2種死四
//012345
//xooox  連續活三
// xooox 連續活三
//xoxoox 不連續活三
//xooxox 不連續活三
//xoooox 活四
//oooox  死四
//xxoooo 死四

void Check6(int y, int x, int type){
	start_y=y;
	start_x=x;
	VH_TYPE=type;
	if(getn(3)=='o'){
		if(getn(4)=='o'){
			if(getn(5)=='o'){
				if(getn(2)=='o'){
					if(getn(1)=='x'){
						D4++;
					}
				}

			}else{
				if(getn(2)=='o'){
					if(getn(1)=='o'){
						if(getn(0)=='x'){
							L4++;
						}
					}else{
						L31++;
					}
				}else{
					if(getn(1)=='o'){
						if(getn(0)=='x'){
							L32++;
						}

					}

				}
			}
		}else{
			if(getn(2)=='o'){
				if(getn(1)=='o'){
					if(getn(0)=='o'){
						D4++;
					}else{
						L31++;
					}
				}
			}

		}

	}else{
		if(getn(4)=='o' && getn(5)=='x'){
			if(getn(2)=='o' && getn(1)=='o'){
				if(getn(0)=='x'){
					L32++;
				}

			}
		}
	}
}

//5點斜線方向1種連續活三,2種死四
void Check5(int y, int x, int type){
	start_y=y;
	start_x=x;
	VH_TYPE=type;

	if(getn(2)=='o'){
		if(getn(3)=='o'){
			if(getn(4)=='o'){
				if(getn(1)=='o'){
					if(getn(0)=='x'){
						D4++;
					}
				}

			}else{
				if(getn(1)=='o'){
					if(getn(0)=='o'){
						D4++;
					}
					else{
						L31++;
					}
				}
			}
		}
	}
}

void PrintNumber(int n){
	switch(n){
		case 1:break;
		case 2:printf("雙"); break;
		case 3:printf("參"); break;
		case 4:printf("肆"); break;
		case 5:printf("伍"); break;
		case 6:printf("陸"); break;
		case 7:printf("柒"); break;
		case 8:printf("捌"); break;
		case 9:printf("玖"); break;
		default:printf("拾"); break;
	}
}

int main(){

	scanf("%s%s%s%s%s%s%s",
			&d[0][0],&d[1][0],&d[2][0],&d[3][0],
			&d[4][0],&d[5][0],&d[6][0]);

	for(int i=0;i<7;i++){
		//檢查水平7點
		Check7(i, 0, 0);

		//檢查垂直7點
		Check7(0, i, 1);
	}

	//檢查7點的斜線
	Check7(6, 0, 2);
	//檢查7點的反斜線
	Check7(0, 0, 3);


	//檢查6點的斜線
	Check6(5,0,2);
	Check6(6,1,2);
	//檢查6點的反斜線
	Check6(0,1,3);
	Check6(1,0,3);

	//檢查5點的斜線
	Check5(4,0,2);
	Check5(6,2,2);
	//檢查5點的反斜線
	Check5(0,2,3);
	Check5(2,0,3);

	if(D4>0){
		PrintNumber(D4);
		printf("死四");
	}
	if(L4>0){
		PrintNumber(L4);
		printf("活四");
	}
	int L3=L31+L32;
	if(L3>0){
		PrintNumber(L3);
		printf("活三");
	}

}
C++

Comments

No comments yet. Why don’t you start the discussion?

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *