黑白棋游戏

 黑白棋游戏

源程序名            game.???(pas, c, cpp)

可执行文件名        game.exe

输入文件名          game.in

输出文件名          game.out

【问题描述】

    黑白棋游戏的棋盘由4×4方格阵列构成。棋盘的每一方格中放有1枚棋子,共有8枚白棋子和8枚黑棋子。这16枚棋子的每一种放置方案都构成一个游戏状态。在棋盘上拥有1条公共边的2个方格称为相邻方格。一个方格最多可有4个相邻方格。在玩黑白棋游戏时,每一步可将任何2个相邻方格中棋子互换位置。对于给定的初始游戏状态和目标游戏状态,编程计算从初始游戏状态变化到目标游戏状态的最短着棋序列。

【输入】

    输入文件共有8行。前四行是初始游戏状态,后四行是目标游戏状态。每行4个数分别表示该行放置的棋子颜色。“0”表示白棋;“1”表示黑棋。

【输出】

    输出文件的第一行是着棋步数n。接下来n行,每行4个数分别表示该步交换棋子的两个相邻方格的位置。例如,abcd表示将棋盘上(a,b)处的棋子与(c,d)处的棋子换位。

【样例】

    game.in                     game.out

    1111                            4

    0000                            1222

    1110                            1424

    0010                            3242

    1010                            4344

    0101

    1010

    0101

================

宽搜

状态的存储,

和八数码一样,这道题难在状态的存储

本题可以将状态转化为2进制...可将空间优化到1..2^16.

---------------

位操作的实现...

================

type
  arr=array[1..4,1..4]of longint;
  
var
  map,map1:array[1..4,1..4]of longint;
  f:array[1..65536]of boolean;
  aim,start:longint;
  h:array[1..200000,1..3]of longint;
  
procedure init;
begin
  assign(input,'game.in');
  assign(output,'game.out');
  reset(input); rewrite(output);
end;

procedure terminate;
begin
  close(input); close(output);
  halt;
end;

function gethash(a:arr):longint;
var
  i,j:longint;
begin
  gethash:=0;
  for i:=1 to 4 do
    for j:=1 to 4 do
      gethash:=(gethash)shl 1+a[i,j];
end;

function get(t:longint):arr;
var
  i,j:longint;
  //l,x,y:longint;
begin
  for i:=1 to 4 do
    for j:=1 to 4 do
      begin
        get[i,j]:=(t shr (16-(i-1)*4-j))and 1;
      end;
end;

procedure change(x,y,x_,y_:longint;var b:arr);
var
  tem:longint;
begin
  tem:=b[x,y];
  b[x,y]:=b[x_,y_];
  b[x_,y_]:=tem;
end;

procedure print(t,n:longint);
begin
  if h[t,2]<>0 then print(h[t,2],n+1);
  if h[t,2]=0 then begin writeln(n); exit; end;
  writeln(h[t,3]);
end;

procedure bfs;
var
  l,r,i,j,hash_:longint;
  a,b:arr;
begin
  l:=0; r:=1;
  h[1,1]:=start;
  h[1,2]:=0;
  h[1,3]:=0;
  
  repeat
    inc(l);
    a:=get(h[l,1]);
    
    for i:=1 to 4 do
      for j:=1 to 3 do
        begin
          b:=a;
          change(i,j,i,j+1,b);
          hash_:=gethash(b);
          if f[hash_] then
            begin
              f[hash_]:=false;
              inc(r);
              h[r,1]:=hash_;
              h[r,2]:=l;
              h[r,3]:=i*1000+j*100+i*10+(j+1);
              if aim=hash_ then
                begin
                  print(r,0);
                  terminate;
                end;
            end;
        end;
    for i:=1 to 3 do
      for j:=1 to 4 do
        begin
          b:=a;
          change(i,j,i+1,j,b);
          hash_:=gethash(b);
          if f[hash_] then
            begin
              f[hash_]:=false;
              inc(r);
              h[r,1]:=hash_;
              h[r,2]:=l;
              h[r,3]:=i*1000+j*100+(i+1)*10+j;
              if aim=hash_ then
                begin
                  print(r,0);
                  terminate;
                end;
            end;
        end;
  until l>=r;
end;

procedure main;
var
  ch:char;
  i,j:longint;
begin
  fillchar(f,sizeof(f),true);
  
  for i:=1 to 4 do
    begin
      for j:=1 to 4 do
        begin
          read(ch);
          map[i,j]:=ord(ch)-ord('0');
        end;
      readln;
    end;
    
  start:=gethash(map);
  f[start]:=false;
  
  for i:=1 to 4 do
    begin
      for j:=1 to 4 do
        begin
          read(ch);
          map1[i,j]:=ord(ch)-ord('0');
        end;
      readln;
    end;
  aim:=gethash(map1);
  
  bfs;
end;

begin
  init;
  main;
  terminate;
end.    


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值