Rabu, 25 April 2012

membuat game catur


         Kali ini saya akan berbagi tentang bagaimana membangun sebuah game, dan pada tulisan ini saya akan membahas game catur yang telah saya buat sendiri pada Tugas di kampus saya.

1. Bahasa dan Program Editor
            Permainan Horse chess ini menggunakan bahasa pemrograman Prolog, dengan program editor yang saya gunakan adalah Strawberry Prolog.
           
2. Initial State
Initial State yang digunakan sebagai acuan untuk membuat program Horse chess adalah pada buah catur yang berisi mayoritas kuda.
Di sini saya menggunakan papan catur biasa tetapi tiap-tiap perwiranya diganti dengan kuda kecuali ratu. Pion atau bidak terletak dibaris depan selayaknya catur pada umumnya, dan kuda dibaris belakang menemani 1 raja dan 1 ratu.
Game ini akan mengasah otak pemainnya. Pemain dipaksa untuk menerapkan strategi yang tepat untuk memenangkan game ini. Permainan ini hanya dapat dimainkan oleh satu pemain, sedangkan Komputer bertindak sebagai lawan.

3. Aturan (Rule)
            Setiap permainan pasti memiliki aturan, begitu juga dengan permainan ini.  Ada beberapa aturan yang terdapat dalam permainan ini, diantaranya adalah :
  1. pemain (user) dapat menentukan akan bermain dengan warna putih atau hitam, dan seperti catur pada umumnya, putih jalan terlebih dahulu.
  2. Pemain hanya dapat melangkah satu kali kemudian komputer yang mendapat giliran melangkah, begitu seterusnya.
  3. Disini hanya ada 4 tipe buah catur, yaitu : pion, kuda, ratu dan raja.
  4. Langkah pion yaitu jalan 1 langkah kedepan dengan kondisi petak didepan harus  kosong (tidak ada yang menghalangi). Jika ingin memakan lawan, pion melangkah diagonal kedepan sebanyak 1 petak.
  5. Ketika pion berhasil berjalan sampai  garis belakang daerah lawan, maka pion secara otomatis berganti dengan ratu.
  6. Langkah kuda yaitu membentuk huruf L.
  7. Langkah ratu yaitu vertical, horizontal dan diagonal.
  8. Langkah raja sama dengan ratu tetapi hanya boleh melangkah 1 petak saja.
  9. komputer diberi pembelajaran untuk menghalagi jalan user mencapai tujuan (goal).
  10. komputer juga diberi pembelajaran untuk memenangkan permaianan ini
  11. Untuk memenangkan permainan ini, pemain harus membuat raja lawan tidak dapat mengelak untuk dimakan (skak mat).

3. Tujuan ( Goal )
Tujuan (goal) untuk menyelesaikan permainan ini adalah membuat
Lawan menyerah dengan membuat raja tidak dapat mengelak untuk dimakan.




4. Kecerdasan Buatan ( AI )
            Kecerdasan buatan atau sering disebut sebagai AI pada permaianan ini terletak pada computer, yang bertindak sebagai lawan. Computer akan berusaha mengalakan pemain (user) dan dapat menyusun strategi sendiri agar menjadi pemenang.

5.      Batas Usia
Semua orang dapat menjadi pemain (user) dan memainkan permainan
ini. Karena permainan ini mengasah keterampilan otak dalam menyusun strategi, maka tidak ada batasan umur yang diberikan.

6.      Strawberry Prolog
            Strawberry Prolog merupakan sebuah bahasa pemrograman logika yang memiliki Object Oriented Language. Pada prolog ini tidak terdapat prosedur, hanya terdapat kumpulan data yang akan diolah. Untuk menggunakan strawberry prolog tidak dilakukan instalasi. Programmer dapat meng-unduhnya secara gratis di website resminya. Namun karena penggunaannya yang gratis, pada strawberry prolog ini, games horse chess tidak dapat membentuk sebuah file execute (exe). Jadi program dapat dijalankan dengan membuka file strawberry prolog (spj) di dalam strawberry prolog itu sendiri.

7.      Analisa Pembuatan Program

            Pembuatan permainan ini sebenarnya cukup rumit tetapi akan mudah untuk dipelajari, langkah pertama tentu saya membuat desain gambar sebuah papan catur 8 x 8 kotak yang berselang-seling dengan warna coklat muda dan coklat tua. Kemudian saya membuat desain untuk pion putih dan hitam. Lalu membuat desain untuk kuda putih dan hitam, membuat ratu untuk putih dan hitam dan yang terakhir adalah raja putih dan hitam yang berbentuk seperti Pegasus (kuda bersayap).
            Setelah semua gambar visual yang dibutuhkan selesai dibuat, kita hanya tinggal “memanggil” gambar tersebut kedalam prolog pada beberapa perintah. Perlu diingat banhwa file gambar tersebut harus didalam folder yang sama dengan listing program.spj yang akan kita buat.
            Kemudian saya memberikan hak langkah untuk masing-masing buah catur dengan beberapa kondisi dan aturan didalamnya.lalu saya membuat beberapa level kecerdasan AI yaitu beginner, normal, advanced dan expert yang tentunya memiliki tingkat kesulitan untuk dikalahkan yang berbeda-beda.
            Kemudian saya memberikan aturan khusus untuk raja, yaitu ketika raja berhasil dimakan, maka permainan berakhir. Untuk lebih jelasnya saya telah menyiapkan listing program pada lembar selanjutnya.



1.      Kesimpulan
            Permainan horse chess yang saya buat ini adalah sebuah permainan hiburan yang juga dapat mengasah otak. Karena pemain harus menyusun strategi agar dapat mengalahkan AI yang saya buat pada lawan (computer)

2.      Saran
            Untuk setiap pemain (user) yang memainkan permainan ini, diharapkan lebih teliti serta dapat menggunakan strategi yang tepat dan cerdas agar dapat mengalahkan AI pada komputer


4.               Listing Program :


% If you want to understand this program look at
% its rough variant "chess rough.pro".
% It is easier to understand because
% "Chess.spj" contains too many details.

level(1, 2, 1, 5).
level(2, 3, 3, 15).
level(3, 4, 6, 30).
level(4, 5, 30, 150).

?-
  G_AuCh=0,
  G_Level=2,
  G_Deep=0,
  G_Move=0,
  G_Forward=0,
  G_I=0,
  G_Play_with_Blacks=0,
  G_Play_with_Computer=1,
  array(val,100,0),
  array(maximum,100,0),
  array(i,1000,0),
  array(j,1000,0),
  array(x,1000,0),
  array(y,1000,0),
  array(val2,1000,0),
  array(index,1000,0),
  G_chessboard is bitmap_image("chess_pic\\chessboard.bmp",_),
  G_squareW is bitmap_image("chess_pic\\squareW.bmp",_),
  G_squareB is bitmap_image("chess_pic\\squareB.bmp",_),
  G_PawnW1 is bitmap_image("chess_pic\\PawnW1.bmp",_),
  G_PawnW2 is bitmap_image("chess_pic\\PawnW2.bmp",_),
  G_PawnB1 is bitmap_image("chess_pic\\PawnB1.bmp",_),
  G_PawnB2 is bitmap_image("chess_pic\\PawnB2.bmp",_),
  G_KingW1 is bitmap_image("chess_pic\\KingW1.bmp",_),
  G_KingW2 is bitmap_image("chess_pic\\KingW2.bmp",_),
  G_KingB1 is bitmap_image("chess_pic\\KingB1.bmp",_),
  G_KingB2 is bitmap_image("chess_pic\\KingB2.bmp",_),
  G_QueenW1 is bitmap_image("chess_pic\\QueenW1.bmp",_),
  G_QueenW2 is bitmap_image("chess_pic\\QueenW2.bmp",_),
  G_QueenB1 is bitmap_image("chess_pic\\QueenB1.bmp",_),
  G_QueenB2 is bitmap_image("chess_pic\\QueenB2.bmp",_),
 G_KnightW1 is bitmap_image("chess_pic\\KnightW1.bmp",_),
  G_KnightW2 is bitmap_image("chess_pic\\KnightW2.bmp",_),
  G_KnightB1 is bitmap_image("chess_pic\\KnightB1.bmp",_),
  G_KnightB2 is bitmap_image("chess_pic\\KnightB2.bmp",_),
 window(G_Win,_,chess_func(_),"Horse Chess",10,150,512,550).

levelm(init):-
  menu(normal,_,_,l2(_),"&Beginner"),
  menu(checked,_,_,l3(_),"&Normal"),
  menu(normal,_,_,l4(_),"&Advanced"),
  menu(normal,_,_,l5(_),"&Expert"),
  menu(separator, _,_,fail(_),_),
  menu(normal,_,_,automatic_change(_),"Automatic change of the Deep").

l2(press):-change_level(1).
l3(press):-change_level(2).
l4(press):-change_level(3).
l5(press):-change_level(4).

automatic_change(press):-
  G_AuCh:=1-G_AuCh,
  (G_AuCh=0->
    modify_menu(G_Menu1,6,normal,_)
  else
    modify_menu(G_Menu1,6,checked,_)
  ).

change_level(M):-
  G_Deep:=0,
  modify_menu(G_Menu1,G_Level,normal,_),
  G_Level:=M, modify_menu(G_Menu1,M,checked,_).

changem(init):-
  menu(normal,_,_,play_with_blacks(_),"&Play with Blacks"),
  menu(checked,_,_,play_with_computer(_),"&Play with the computer").

play_with_blacks(press):-
  (G_Play_with_Computer=0->
    message("", "You can change the side only when you play with the computer!", s)
  else
    change_side,
    pos(G_Move, C1, WantsStalemate, Pos),
    G_WantsStalemate:=0-WantsStalemate,
    opposite(C1, C2),
    computer(C1,C2,Pos)
  ).

change_side:-
  G_Play_with_Blacks:=1-G_Play_with_Blacks,
  (G_Play_with_Blacks=0->
    modify_menu(G_Menu2,1,normal,_)
  else
    modify_menu(G_Menu2,1,checked,_)
  ).

play_with_computer(press):-
  G_Play_with_Computer:=1-G_Play_with_Computer,
  (G_Play_with_Computer=0->
    modify_menu(G_Menu2,2,normal,_)
  else
    modify_menu(G_Menu2,2,checked,_)
  ).

back(press):-
  G_Move:=G_Move - 1,
  (G_Move=0->
    modify_menu(G_Win,3,grayed,_),
    draw_menu_bar(_)
  ),
  (G_Forward=0->
    modify_menu(G_Win,4,normal,_),
    draw_menu_bar(_)
  ),
  G_Forward:=G_Forward + 1,
  set_some_text,
  update_window(_).

forward(press):-
  (G_Move=0->
    modify_menu(G_Win,3,normal,_),
    draw_menu_bar(_)
  ),
  G_Move:=G_Move + 1,
  G_Forward:=G_Forward - 1,
  (G_Forward=0->
    modify_menu(G_Win,4,grayed,_),
    draw_menu_bar(_)
  ),
  set_some_text,
  update_window(_).

set_some_text:-
  pos(G_Move, C, _, _),
  (G_Play_with_Blacks=\=true_value(C=b)->
    change_side
  ),
  (C=b->
    set_text("Play with Blacks", _)
  else (C=w->
    set_text("Play with Whites", _)
  else
    set_text("Game Over", _)
  )).

set_pos(C, Pos) :-
  (G_Move=0->
    modify_menu(G_Win,3,normal,_),
    draw_menu_bar(_)
  ),
  (G_Forward>0->
    modify_menu(G_Win,4,grayed,_),
    draw_menu_bar(_)
  ),
  G_Move:=G_Move+1,
  G_Forward:=0,
  write(pos(G_Move, C, G_WantsStalemate, Pos)),nl,
  retractall(pos(G_Move,_,_,_)),
  assert(pos(G_Move,C,G_WantsStalemate,Pos)).

chess_func(init):-
  menu(pop_up, G_Menu1,_,levelm(_),"&Level"),
  menu(pop_up, G_Menu2,_,changem(_),"&Change"),
  menu( right, _, _, back(_), "&Back"),
  menu( right, _, _, forward(_), "&Forward"),
  modify_menu(G_Win,3,grayed,_),
  modify_menu(G_Win,4,grayed,_).

chess_func(paint):-
  draw_bitmap(0,0,G_chessboard,_,_),
  fail.

chess_func(paint):-
  pos(G_Move, _, _, Pos),
  mem(Row, Pos,J),
  mem(Fig, Row,I),
  draw_fig(Fig,I,J),
  fail.

chess_func(mouse_click(X,Y)):-
  I :=X//50,
  J :=Y//50,
  I>0, I=<8,
  J>0, J=<8,
  pos(G_Move, C1, WantsStalemate, Pos),
  opposite(C1, C2),
  mem(Row,Pos,J),
  mem(Fig,Row,I),
  (G_I=0 ->
    Fig=[_|C1],
    G_Fig:=Fig,
    clean_field(I, J),
    G_I:=I,
    G_J:=J
  else (can_move(G_Fig,G_I,G_J,I,J,Pos,Fig2), not(Fig2=[_|C1])->
    move0(G_I,G_J,Pos,I,J,Pos2),
    (check(C1, C2, Pos2)->
      message("Bad move", "You are in check after this move", !),
      draw_fig(G_Fig,G_I,G_J),
      G_I:=0,
      fail
    ),
    (J/\6=:=0->
      (G_Fig=[p|C1]->
        draw_fig([q|C1],I,J)
      else (G_Fig=[k|C1], abs(G_I-I)=:=2 ->
        (I=3, Xm=4, Xf=1; I=7, Xm=6, Xf=8),
        clean_field(Xf, J),
        draw_fig([r|C1],Xm,J),
        draw_fig([k|C1],I,J)
      else
        draw_fig(G_Fig,I,J)
      ))
    else
      draw_fig(G_Fig,I,J)
    ),
    val(Fig2,Val),
    G_WantsStalemate:=WantsStalemate+Val,
    (check(C2, C1, Pos2), not(not_mate(C2, C1, Pos2))->
      set_pos(n,Pos2),
      set_text("Mate. You won!", _),
      message("Congratulations", "You won!", !),
      fail
    ),
    (G_Play_with_Computer=1->
      computer(C2,C1,Pos2)
    else
      change_side,
      G_WantsStalemate:=0-G_WantsStalemate,
      set_pos(C2, Pos2),
      set_text(xy(G_I, G_J)+":"+xy(I, J)+ (G_Play_with_Blacks=1-> " (Play with Blacks)" else ""), _),
      G_I:=0
    )
  else
    draw_fig(G_Fig,G_I,G_J),
    G_I:=0
  )).

computer(C2,C1,Pos2):-
    G_I:=0,
    set_text("...", _),
    G_I1:=0,
    (G_Deep=0->level(G_Level,Deep,_,_), G_Deep:=Deep),
    write("Deep="+G_Deep),nl,
    chronometer(_),
    chronometer_steps(_),
    maximum(G_Deep):= -20000,
    Moves:=0,
    (play(C2,C1,Pos2,G_Deep,Moves); true),
    chronometer(Time),
    chronometer_steps(Steps),
    beep,
    write(maximum(G_Deep)+" for "+Time/1000+" seconds ("+Steps+" steps)"),nl,
    (G_AuCh=1->
      level(G_Level,_,Minimum,Maximun),
      (Time<1000*Minimum->
        G_Deep:=G_Deep+1,
        write("Deep+1="+G_Deep),nl
      else (Time>1000*Maximun, G_Deep>2->
        G_Deep:=G_Deep- 1,
        write("Deep-1="+G_Deep),nl
      ))
    ),
    (G_I1=0->
      set_pos(n, Pos2),
      set_text("Stalemate", _),
      message("Stalemate", "I am in stalemate. This gane is draw.", !),
      fail
    ),
    mem(Row1,Pos2,G_J1),
    mem(Fig,Row1,G_I1),
    can_move(Fig,G_I1,G_J1,G_I2,G_J2,Pos2,Fig2),
    val(Fig2,Val),
    G_WantsStalemate:=G_WantsStalemate-Val,
    move0(G_I1,G_J1,Pos2,G_I2,G_J2,Pos3),
    clean_field(G_I1, G_J1),
    mem(Row2,Pos3,G_J2),
    mem(BFig,Row2,G_I2),
    (BFig=[k|C2], abs(G_I1-G_I2)=:=2 ->
      (G_I2=3, XXm=4, XXf=1; G_I2=7, XXm=6, XXf=8),
      clean_field(XXf, G_J2),
      draw_fig([r|C2],XXm,G_J2),
      draw_fig([k|C2],G_I2,G_J2)
    else
      draw_fig(BFig,G_I2,G_J2)
    ),
    (check(C1, C2, Pos3)->
      (not_mate(C1, C2, Pos3)->
        set_text("Check", _)
      else
        set_pos(n, Pos3),
        set_text("You are Mate!", _),
        message("Mate. Game over", "Sorry but you lost this set.", s),
        fail
      )
    else
      set_text(xy(G_I1, G_J1)+":"+xy(G_I2, G_J2)+ (G_Play_with_Blacks=1-> " (Play with Blacks)" else ""), _)
    ),
    (not(mem(Row3,Pos3,J1), mem([F1|C1],Row3,I1), can_move([F1|C1],I1,J1,_,_,Pos3,Fig3), not(Fig3=[_|C1]))->
      set_pos(n, Pos3),
      set_text("Stalemate", _),
      message("Stalemate", "You are in stalemate. This game is draw.", !),
      fail
    ),
    (not(mem(Row4,Pos3,_), mem([F2|_],Row4,_), F2\=k)->
      set_pos(n, Pos3),
      set_text("Tie", _),
      message("Tie", "This game is draw.", !),
      fail
    ),
    set_pos(C1, Pos3).

play(C1,C2,Pos,Deep,Moves):-
  Deep1  is Deep - 1,
  (Deep1=0->
    (val(Deep):=35;
    mem(Row,Pos,J),
    mem([Fig|C1],Row,I),
    can_move([Fig|C1],I,J,X,Y,Pos,[Fig2|C2]),
    take_val(Fig,Fig2,Val2,C1,C2,X,Y,Pos),
    val(Deep):=Val2)
  else
    Moves2:=Moves,
    all_moves(C1,Pos,Deep,I,J,X,Y,Val2,Moves,Moves2),
    move(I,J,Pos,X,Y,Pos2,Val2),
    val(Deep):=Val2,
    (Val2>5000->
      (Deep=:=G_Deep- 1, check(C2, C1, Pos)->
        maximum(Deep1):= -5000
      else
        maximum(Deep1):=0
      )
    else
      maximum(Deep1):= -20000,
      (play(C2,C1,Pos2,Deep1,Moves2); true),
      (maximum(Deep1) =:= -20000->
        (check(C2, C1, Pos2)->
          maximum(Deep1):= -10000-Deep
        else
          maximum(Deep1):= (1 - 2* ((G_Deep-Deep1) mod 2))*G_WantsStalemate
        )
      )
    )
  ),
  %(Deep=G_Deep-> write(xy(I,J)+":"+xy(X,Y)+" is "+ (val(Deep)-maximum(Deep1))), nl),
  (maximum(Deep)<val(Deep)-maximum(Deep1)->  % =< in order to see all best
    maximum(Deep):=val(Deep)-maximum(Deep1),
    (Deep=G_Deep->
      write(xy(I,J)+":"+xy(X,Y)+" is "+ (val(Deep)-maximum(Deep1))), nl,
      G_I1:=I, G_J1:=J,
      G_I2:=X, G_J2:=Y,
      fail
    else (maximum(Deep+1)<val(Deep+1)-maximum(Deep)->  % =< in order to see all best

      fail
    %else
      %write(Deep) % alpha-beta cutting
    ))
  else
    fail
  ),
  !,
  fail.

all_moves(C1,Pos,Deep,_,_,_,_,_,Moves,Moves2):-
  mem(Row,Pos,J),
  mem([Fig|C1],Row,I),
  Sum1:=0,
  can_hit([Fig|C1],I,J,Pos,shadow,no,Sum1),
  can_move([Fig|C1],I,J,X,Y,Pos,Fig2),
  not(Fig2=[_|C1]),
  (Fig2=[p|_]->
    Val is (C1=w-> 60+20*Y else 240- 20*Y)
  else
    val(Fig2,Val)
  ),
  Val2 is Val-Sum1+Deep* (1+sign(Val//18- 1)), % 18 is val(p)
  find_the_right_place(Val2,Moves,Moves2,Place),
  i(Moves2):=I, j(Moves2):=J,
  x(Moves2):=X, y(Moves2):=Y,
  val2(Moves2):=Val2,
  index(Place):=Moves2,
  Moves2:=Moves2+1,
  fail.
all_moves(_,_,_,I,J,X,Y,Val2,Moves,Moves2):-
  for(N, Moves, Moves2- 1),
  I is i(index(N)), J is j(index(N)),
  X is x(index(N)), Y is y(index(N)),
  Val2 is val2(index(N)).

find_the_right_place(Val2,M,M,M):- !.
find_the_right_place(Val2,Moves,Moves2,Place):-
  MovesP is Moves2- 1,
  (val2(index(MovesP))<Val2->
    index(Moves2):=index(MovesP),
    find_the_right_place(Val2,Moves,MovesP,Place)
  else
    Moves2=Place
  ).

can_hit([Fig|C1],I,J,Pos,_,Try,Sum):- % the figure hits
  can_move([Fig|C1],I,J,_,_,Pos,F),
  (F=[Fig2|C]->
    (C=C1->
      Sum:=Sum+8
    else
      val([Fig2|_],Val2),
      val([Fig|_],Val1),
      (Val1<Val2->
        (Fig2=k->
          (Try=no; not_mate(C, C1, Pos)->
            Sum:=Sum+50
          else
            Sum:=Val2
          )
        else
          Sum:=Sum+33
        )
      else
        Sum:=Sum+12
      )
    )
  else
    Sum:=Sum+4
  ),
  fail.
can_hit([Fig|C1],I,J,Pos,Shadow,_,Sum):- % other figures hit it
  can_move([F|C_1],I,J,I0,J0,Pos,[F|C_2]),
  not(F=p, C_1=C_2),
  not(F=k, C_1=C_2),
  (C_2=C1->
    Sum:=Sum+ 4 % 8-4
  else
    val([F|_],Val2),
    val([Fig|_],Val1),
    (Val1>Val2->
      (Fig=k->
        Sum:=Sum- 46 % 50-4
      else
        Sum:=Sum- 29 % 33-4
      )
    else
      Sum:=Sum- 8 % 12-4
    )
  ),
  throw_shadow(Shadow,[F|C_2],I0,J0,I,J,Pos,SumT),
  (C_2=C1->
    Sum:=Sum-SumT
  else
    Sum:=Sum+SumT
  ),
  fail.
can_hit(_,_,_,_,_,_,_).

throw_shadow(shadow,[F|C_2],I1,J1,I2,J2,Pos,Sum):-
  Sum:=0,
  (F=r; F=q),
  (I1=I2->
    (J1<J2->
      move_down(I2,J2,_,_,Pos,Fig)
    else
      move_up(I2,J2,_,_,Pos,Fig)
    )
  else (J1=J2->
    (I1<I2->
      move_right(I2,J2,_,_,Pos,Fig)
    else
      move_left(I2,J2,_,_,Pos,Fig)
    )
  else
    fail
  )),
  hit([F|C_2],Fig,Sum).
throw_shadow(shadow,[F|C_2],I1,J1,I2,J2,Pos,Sum):-
  (F=b; F=q),
  (I1+J1=:=I2+J2->
    (I1<I2->
      move_right_up(I2,J2,_,_,Pos,Fig)
    else
      move_left_down(I2,J2,_,_,Pos,Fig)
    )
  else (I1-J1=:=I2-J2->
    (I1<I2->
      move_right_down(I2,J2,_,_,Pos,Fig)
    else
      move_left_up(I2,J2,_,_,Pos,Fig)
    )
  else
    fail
  )),
  hit([F|C_2],Fig,Sum).
throw_shadow(shadow,[_|_],_,_,_,_,_,_).

hit([Fig|C1],F,Sum):-
  (F=[Fig2|C]->
    (C=C1->
      Sum:=Sum+8
    else
      val([Fig2|_],Val2),
      val([Fig|_],Val1),
      (Val1<Val2->
        (Fig2=k->
          Sum:=Sum+50
        else
          Sum:=Sum+33
        )
      else
        Sum:=Sum+12
      )
    )
  else
    Sum:=Sum+4
  ),
  fail.

move(I1,J1,Pos1,I2,J2,Pos2,Sum):-
  mem(Row, Pos1, J1),
  mem([F1|C1], Row, I1),
  replace(f, Row, Row2,I1),
  replace(Row2, Pos1, Pos1a, J1),
  mem(Row3, Pos1a, J2),
  (J2/\6=:=0->
    (F1=p->
      replace([q|C1], Row3, Row4, I2)
    else (F1=k, abs(I1-I2)=:=2 ->
      (I2=3, Xm=4, Xf=1; I2=7, Xm=6, Xf=8),
      Sum:=Sum+50,
      replace(f, Row3, Row3a, Xf),
      replace([r|C1], Row3a, Row3b, Xm),
      replace([F1|C1], Row3b, Row4, I2)
    else
      replace([F1|C1], Row3, Row4, I2)
    ))
  else
    replace([F1|C1], Row3, Row4, I2)
  ),
  replace(Row4, Pos1a, Pos2,J2),
  (mem([F2|C2], Row3, I2)->
    Sum1:=0,
    can_hit([F2|C2],I2,J2,Pos2,no,no,Sum1),
    Sum:=Sum-Sum1,
    can_hit([F1|C1],I2,J2,Pos2,no,try,Sum)
  else
    can_hit([F1|C1],I2,J2,Pos2,shadow,try,Sum)
  ).

move0(I1,J1,Pos1,I2,J2,Pos2):-
  mem(Row, Pos1, J1),
  mem([F1|C1], Row, I1),
  replace(f, Row, Row2,I1),
  replace(Row2, Pos1, Pos1a, J1),
  mem(Row3, Pos1a, J2),
  (J2/\6=:=0->
    (F1=p->
      replace([q|C1], Row3, Row4, I2)
    else (F1=k, abs(I1-I2)=:=2 ->
      (I2=3, Xm=4, Xf=1; I2=7, Xm=6, Xf=8),
      replace(f, Row3, Row3a, Xf),
      replace([r|C1], Row3a, Row3b, Xm),
      replace([F1|C1], Row3b, Row4, I2)
    else
      replace([F1|C1], Row3, Row4, I2)
    ))
  else
    replace([F1|C1], Row3, Row4, I2)
  ),
  replace(Row4, Pos1a, Pos2,J2).

val(f,0).
val(p,18). % Pawn move
val(d,35). % Pawn double move = 2*val(p)-1
val([p|_],100).
val([h|_],300).
val([q|_],1000).
val([n|_],600). % new queen
val([t|_],700). % new queen and take
val([k|_],10000).

take_val(p,p,60|_).  take_val(p,h,250|_). take_val(p,q,950|_).  take_val(p,k,10000|_).
take_val(k,p,100|_). take_val(k,h,300|_). take_val(k,q,1000|_). take_val(k,k,10000|_).
take_val(h|T):-
  evaluate(300|T).
take_val(q|T):-
  evaluate(1000|T).

evaluate(Val1,Fig,Val,C1,C2,X,Y,Pos):-
  val([Fig|_],Val2),
  (Val2>Val1->
    Val is Val2 - Val1//2
  else (can_move([F|C1],X,Y,_,_,Pos,[F|C2])->
    Val=50
  else
    val([Fig|_],Val)
  )).

%pos(0,w,0,[[rb,hb,bb,qb,kb,bb,hb,rb],[f,pb,f,f,f,f,pb,f],[f,f,f,pb,f,pb,f,f],[pb,f,pb,qw,f,f,f,pb],[f,f,f,f,pw,f,f,f],[f,pw,hw,f,f,hw,f,f],[pw,f,pw,f,f,pw,pw,pw],[rw,f,bw,f,kw,bw,f,rw]]).

pos(0, w, 0,
    [[hb,hb,hb,qb,kb,hb,hb,hb],
     [pb,pb,pb,pb,pb,pb,pb,pb],
     [f,f,f,f,f,f,f,f],
     [f,f,f,f,f,f,f,f],
     [f,f,f,f,f,f,f,f],
     [f,f,f,f,f,f,f,f],
     [pw,pw,pw,pw,pw,pw,pw,pw],
     [hw,hw,hw,qw,kw,hw,hw,hw]]).

clean_field(I, J):-
  ( (I+J) mod 2 =:= 0->
    draw_bitmap(50*I,50*J,G_squareW,_,_)
  else
    draw_bitmap(50*I,50*J,G_squareB,_,_)
  ).

draw_fig(Fig,I,J):-
  N is 1+ (I+J) mod 2,
  fig(Fig, N, Bitmap),
  draw_bitmap(I*50,J*50,Bitmap,_,_).

fig(pb, 1, G_PawnB1).
fig(pw, 1, G_PawnW1).
fig(kb, 1, G_KingB1).
fig(kw, 1, G_KingW1).
fig(qb, 1, G_QueenB1).
fig(qw, 1, G_QueenW1).
fig(hb, 1, G_KnightB1).
fig(hw, 1, G_KnightW1).
fig(pb, 2, G_PawnB2).
fig(pw, 2, G_PawnW2).
fig(kb, 2, G_KingB2).
fig(kw, 2, G_KingW2).
fig(qb, 2, G_QueenB2).
fig(qw, 2, G_QueenW2).
fig(hb, 2, G_KnightB2).
fig(hw, 2, G_KnightW2).

R is xy(X, Y):- R:=string_from_ASCII(X+first_ASCII("A")- 1)+ (9-Y).

mem(E,[E,_,_,_,_,_,_,_],1).
mem(E,[_,E,_,_,_,_,_,_],2).
mem(E,[_,_,E,_,_,_,_,_],3).
mem(E,[_,_,_,E,_,_,_,_],4).
mem(E,[_,_,_,_,E,_,_,_],5).
mem(E,[_,_,_,_,_,E,_,_],6).
mem(E,[_,_,_,_,_,_,E,_],7).
mem(E,[_,_,_,_,_,_,_,E],8).

replace(X,[_,A,B,C,D,E,F,G],[X,A,B,C,D,E,F,G],1).
replace(X,[A,_,B,C,D,E,F,G],[A,X,B,C,D,E,F,G],2).
replace(X,[A,B,_,C,D,E,F,G],[A,B,X,C,D,E,F,G],3).
replace(X,[A,B,C,_,D,E,F,G],[A,B,C,X,D,E,F,G],4).
replace(X,[A,B,C,D,_,E,F,G],[A,B,C,D,X,E,F,G],5).
replace(X,[A,B,C,D,E,_,F,G],[A,B,C,D,E,X,F,G],6).
replace(X,[A,B,C,D,E,F,_,G],[A,B,C,D,E,F,X,G],7).
replace(X,[A,B,C,D,E,F,G,_],[A,B,C,D,E,F,G,X],8).

check(C1, C2, Pos):-
  mem(Row,Pos,J),
  mem([k|C1],Row,I),
  can_move([Fig|C1],I,J,_,_,Pos,[Fig|C2]).

not_mate(C1, C2, Pos):-
  mem(Row,Pos,J),
  mem([Fig|C1],Row,I),
  can_move([Fig|C1],I,J,X,Y,Pos,Fig2),
  not(Fig2=[_|C1]),
  move0(I,J,Pos,X,Y,Pos2),
  not(check(C1, C2, Pos2)).

opposite(w, b).
opposite(b, w).

can_move([h|_], X1,Y1,X2,Y2,Pos,Fig):-
  (X2 is X1+1; X2 is X1 - 1),
  (Y2 is Y1+2; Y2 is Y1 - 2),
  mem(Row,Pos,Y2),
  mem(Fig,Row,X2).

can_move([h|_], X1,Y1,X2,Y2,Pos,Fig):-
  (X2 is X1+2; X2 is X1 - 2),
  (Y2 is Y1+1; Y2 is Y1 - 1),
  mem(Row,Pos,Y2),
  mem(Fig,Row,X2).

can_move([k|Color], X1,Y1,X2,Y2,Pos,Fig):-
  (X2 is X1+1; X2 is X1 - 1; X2=X1),
  (Y2 is Y1+1; Y2 is Y1 - 1;Y2=Y1),
  not(X1=X2,Y1=Y2),
  mem(Row,Pos,Y2),
  mem(Fig,Row,X2),
  opposite(Color, C2),
  (Fig=[k| C2]; not(can_move([F|Color],X2,Y2,_,_,Pos,[F|C2]))).

can_move([k|Color], 5,Y,X2,Y,Pos,f):-
  (Y = 1, Color=b, C2=w; Y= 8, Color=w, C2=b),
  mem(Row,Pos,Y),
  (X2 = 3, mem(f,Row,2), Xn=4, Xr=1; X2 = 7, Xn=6, Xr=8),
  mem(f,Row,X2),
  mem(f,Row,Xn),
  mem([r|Color],Row,Xr),
  not(can_move([Fig|Color],X2,Y,_,_,Pos,[Fig|C2])),
  not(can_move([Fig|Color],Xn,Y,_,_,Pos,[Fig|C2])),
  not(can_move([Fig|Color], 5,Y,_,_,Pos,[Fig|C2])).

can_move(pw, X,Y1,X,Y2,Pos,Fig):-
  Yn is Y1 - 1,
  mem(Row,Pos,Yn),
  mem(f,Row,X),
  (Y2=Yn, (Y1=2->Fig=nb else Fig=p)
  ;
  Y1=7, mem(Row2,Pos,5), mem(f,Row2,X), Y2=5, Fig=d
  ).

can_move(pb, X,Y1,X,Y2,Pos,Fig):-
  Yn is Y1 + 1,
  mem(Row,Pos,Yn),
  mem(f,Row,X),
  (Y2=Yn, (Y1=7->Fig=nw else Fig=p)
  ;
  Y1=2, mem(Row2,Pos,4), mem(f,Row2,X), Y2=4, Fig=d
  ).

can_move(pw, X1,Y1,X2,Y2,Pos,[F1|C]):-
  Y2 is Y1 - 1,
  mem(Row,Pos,Y2),
  (X2 is X1+1;X2 is X1 - 1),
  mem([F2|C],Row,X2),
  (Y2=1, F2\=k->F1=t else F1=F2).

can_move(pb, X1,Y1,X2,Y2,Pos,[F1|C]):-
  Y2 is Y1 + 1,
  mem(Row,Pos,Y2),
  (X2 is X1+1;X2 is X1 - 1),
  mem([F2|C],Row,X2),
  (Y2=8, F2\=k->F1=t else F1=F2).

can_move([r|_], X1,Y1,X2,Y2,Pos,Fig):-
  move_up(X1,Y1,X2,Y2,Pos,Fig);
  move_down(X1,Y1,X2,Y2,Pos,Fig);
  move_left(X1,Y1,X2,Y2,Pos,Fig);
  move_right(X1,Y1,X2,Y2,Pos,Fig).

can_move([b|_], X1,Y1,X2,Y2,Pos,Fig):-
  move_left_up(X1,Y1,X2,Y2,Pos,Fig);
  move_right_down(X1,Y1,X2,Y2,Pos,Fig);
  move_left_down(X1,Y1,X2,Y2,Pos,Fig);
  move_right_up(X1,Y1,X2,Y2,Pos,Fig).

can_move([q|_], X1,Y1,X2,Y2,Pos,Fig):-
  move_up(X1,Y1,X2,Y2,Pos,Fig);
  move_down(X1,Y1,X2,Y2,Pos,Fig);
  move_left(X1,Y1,X2,Y2,Pos,Fig);
  move_right(X1,Y1,X2,Y2,Pos,Fig);
  move_left_up(X1,Y1,X2,Y2,Pos,Fig);
  move_right_down(X1,Y1,X2,Y2,Pos,Fig);
  move_left_down(X1,Y1,X2,Y2,Pos,Fig);
  move_right_up(X1,Y1,X2,Y2,Pos,Fig).

move_up(X,Y1,X,Y2,Pos,Fig2):-
   Y is Y1 - 1,
   mem(Row,Pos,Y),
   mem(Fig,Row,X),
   (Fig=f ->
     (Y2 =Y, Fig2=Fig; move_up(X,Y,X,Y2,Pos,Fig2))
   else
     Y2=Y, Fig2=Fig
   ).

move_down(X,Y1,X,Y2,Pos,Fig2):-
  Y is Y1 + 1,
  mem(Row,Pos,Y),
  mem(Fig,Row,X),
  (Fig=f ->
    (Y2 =Y, Fig2=Fig; move_down(X,Y,X,Y2,Pos,Fig2))
  else
    Y2=Y, Fig2=Fig
  ).

move_left(X1,Y,X2,Y,Pos,Fig2):-
  X is X1 - 1,
  mem(Row,Pos,Y),
  mem(Fig,Row,X),
  (Fig=f ->
    (X2=X, Fig2=Fig; move_left(X,Y,X2,Y,Pos,Fig2))
  else
    X2=X, Fig2=Fig
  ).

move_right(X1,Y,X2,Y,Pos,Fig2):-
  X is X1 + 1,
  mem(Row,Pos,Y),
  mem(Fig,Row,X),
  (Fig=f ->
    (X2=X, Fig2=Fig; move_right(X,Y,X2,Y,Pos,Fig2))
  else
    X2=X, Fig2=Fig
  ).

move_left_up(X1,Y1,X2,Y2,Pos,Fig2):-
  X is X1 - 1, Y is Y1 - 1,
  mem(Row,Pos,Y),
  mem(Fig,Row,X),
  (Fig=f ->
    (X2=X, Y2=Y, Fig2=Fig; move_left_up(X,Y,X2,Y2,Pos,Fig2))
  else
    X2=X, Y2=Y, Fig2=Fig
  ).

move_left_down(X1,Y1,X2,Y2,Pos,Fig2):-
  X is X1 - 1, Y is Y1 + 1,
  mem(Row,Pos,Y),
  mem(Fig,Row,X),
  (Fig=f ->
    (X2=X, Y2=Y, Fig2=Fig; move_left_down(X,Y,X2,Y2,Pos,Fig2))
  else
    X2=X, Y2=Y, Fig2=Fig
  ).

move_right_up(X1,Y1,X2,Y2,Pos,Fig2):-
  X is X1 + 1, Y is Y1 - 1,
  mem(Row,Pos,Y),
  mem(Fig,Row,X),
  (Fig=f ->
    (X2=X, Y2=Y, Fig2=Fig; move_right_up(X,Y,X2,Y2,Pos,Fig2))
  else
    X2=X, Y2=Y, Fig2=Fig
  ).

move_right_down(X1,Y1,X2,Y2,Pos,Fig2):-
  X is X1 + 1, Y is Y1 + 1,
  mem(Row,Pos,Y),
  mem(Fig,Row,X),
  (Fig=f ->
    (X2=X, Y2=Y, Fig2=Fig; move_right_down(X,Y,X2,Y2,Pos,Fig2))
  else
    X2=X, Y2=Y, Fig2=Fig
  ).

Open Panel

Blogroll