2010-12-04 4 views
4

J'ai un tableau unidimensionnel qui signifie table d'échecs. Je voudrais trouver toutes les positions que le chevalier pourrait attaquer. Par exemple, ont 3x3 table d'échecs (K est Knight, X est la position d'attaque):prologue, attaque de chevalier

--------------- 
| X | | | 
--------------- 
| | | K | 
--------------- 
| X | | | 
--------------- 

et pour cette table, dans le programme de Prolog je voudrais avoir un tableau:

------------------------------------- 
| X | | | | | K | X | | | 
------------------------------------- 

Je veux d'écrire le programme universel pour tous les cas - table 3x3, 4x4, 5x5, etc.

J'ai essayé:

control(Table, N, Pos, NewTable) :- insert(Table, Pos, 'k' , TempTable1, 1), 
        insert(TempTable1, Pos-N*2+1, 'x' , TempTable2, 1), 
        insert(TempTable2, Pos-N*2-1, 'x' , TempTable3, 1), 
        insert(TempTable3, Pos-N +2, 'x' , TempTable4, 1), 
        insert(TempTable4, Pos-N -2, 'x' , TempTable5, 1), 
        insert(TempTable5, Pos+N*2+1, 'x' , TempTable6, 1), 
        insert(TempTable6, Pos+N*2-1, 'x' , TempTable7, 1), 
        insert(TempTable7, Pos+N +2, 'x' , TempTable8, 1), 
        insert(TempTable8, Pos+N -2, 'x' , NewTable, 1). 

Il ya N - est la taille de la table (3), position Pos - chevalier. "Insérer" est OK, mais "contrôle" ne fonctionne pas correctement:

?- control([0,0,0,0,0,0,0,0,0], 3, 6, R). 
R = [x, 0, 0, 0, x, k, x, 0, 0]. 

devrait être R = [x, 0, 0, 0, 0, k, x, 0, 0].

Des idées, comment changer le prédicat "contrôle"?

+1

Je suppose que cela sera beaucoup plus facile si vous modélisez la table en tant que tableau 2d et passez les coordonnées X et Y à 'control'. – Cephalopod

Répondre

1

Enlever les inserts jusqu'à ce que le x rogue disparaisse. Cela devrait vous dire où est le problème.

EDIT: Ah-ha! Cela aurait dû m'arriver avant. Vous ne coupez pas les mouvements du chevalier quand ils passent le bord gauche ou droit du plateau, donc le chevalier monte au rang supérieur, puis deux à droite, qui s'enroule autour du rang intermédiaire et place le chevalier juste à côté de lui. position de départ. insert peut uniquement couper le haut et le bas car il ne voit qu'un tableau; il ne sait pas quelle est la largeur du plateau.

+0

Oui, je pourrais enlever la ligne "insert (TempTable3, Pos-N +2, 'x', TempTable4, 1)" mais cette ligne est correcte pour l'autre position de chevalier. – Martynas

+0

J'ai modifié ma réponse. BTW, la ligne est toujours incorrecte pour, par exemple, «contrôle ([0,0,0,0,0,0,0,0,0], 3, 5, R).». En fait, cela produira * deux * cellules "x" malhonnêtes. –

0

Je suis d'accord avec Arian. Il semble vraiment beaucoup plus facile d'utiliser deux coordonnées. Mais si vous voulez vraiment tout garder tel quel, j'ai trouvé quelque chose qui me semble être une solution.

Vous n'avez pas écrit quoi que ce soit au sujet de votre prédicat insert/5, donc je considère que vous avez ceci:

insert(A, Pos, H, A, X) :- 
    Pos < 1, 
    !. 
insert([], Pos, H, [], N) :- 
    !. 
insert([H1|T1], Pos, H, [H|T1], N) :- 
    N =:= Pos, 
    !. 
insert([H1|T1], Pos, H, [H1|T2], N) :- 
    N < Pos, 
    N2 is N + 1, 
    insert(T1, Pos, H, T2, N2). 

Pour aider avec les coordonnées, je l'ai écrit un prédicat qui vous dit ligne et une colonne d'une position: De cette façon, vous pouvez obtenir la ligne + colonne du chevalier, calculer la ligne + la colonne de la nouvelle position d'attaque et les comparer. Si c'est correct - vous insérez, si pas correct - vous ignorez l'insertion.

control(Table, N, Pos, NewTable) :- 
    insert(Table, Pos, 'k' , TempTable1, 1), 
    getposition(N, Pos, Row1, Column1), 

    getposition(N, Pos-N*2+1,RowA, ColumnA), 
    (RowA =:= Row1 - 2, ColumnA =:= Column1 + 1,!, 
    insert(TempTable1, Pos-N*2+1, 'x' , TempTable2, 1);TempTable2 = TempTable1),  

    getposition(N, Pos-N*2-1,RowB, ColumnB), 
    (RowB =:= Row1 - 2, ColumnB =:= Column1 - 1,!, 
    insert(TempTable2, Pos-N*2-1, 'x' , TempTable3, 1);TempTable3 = TempTable2), 

    getposition(N, Pos-N + 2,RowC, ColumnC), 
    (RowC =:= Row1 - 1, ColumnC =:= Column1 + 2,!, 
    insert(TempTable3, Pos-N +2, 'x' , TempTable4, 1);TempTable4 = TempTable3), 

    getposition(N, Pos-N - 2,RowD, ColumnD),  
    (RowD =:= Row1 - 1, ColumnD =:= Column1 - 2,!, 
    insert(TempTable4, Pos-N -2, 'x' , TempTable5, 1); TempTable5 = TempTable4), 

    getposition(N, Pos+N*2+1,RowE, ColumnE), 
    (RowE =:= Row1 + 2, ColumnE =:= Column1 + 1,!, 
    insert(TempTable5, Pos+N*2+1, 'x' , TempTable6, 1); TempTable6 = TempTable5), 

    getposition(N, Pos+N*2-1,RowF, ColumnF),  
    (RowF =:= Row1 + 2, ColumnF =:= Column1 - 1,!, 
    insert(TempTable6, Pos+N*2-1, 'x' , TempTable7, 1); TempTable7 = TempTable6), 

    getposition(N, Pos+N + 2,RowG, ColumnG), 
    (RowG =:= Row1 + 1, ColumnG =:= Column1 + 2,!, 
    insert(TempTable7, Pos+N +2, 'x' , TempTable8, 1); TempTable8 = TempTable7), 

    getposition(N, Pos+N - 2,RowH, ColumnH), 
    (RowH =:= Row1 + 1, ColumnH =:= Column1 - 2,!, 
    insert(TempTable8, Pos+N -2, 'x' , NewTable, 1); NewTable = TempTable8). 

Ceci est probablement pas la meilleure solution, car il est lourd et mes compétences Prolog sont limitées, mais au moins ça marche!

?- control([0,0,0,0,0,0,0,0,0], 3, 6, R). 
R = [x, 0, 0, 0, 0, k, x, 0, 0]. 

?- control([0,0,0,0,0,0,0,0,0], 3, 5, R). 
R = [0, 0, 0, 0, k, 0, 0, 0, 0]. 
0

un serait faire quelque chose comme approche différente ceci:

knight_in_range(X,Y):- 
    knight_move(X,Y,Xn,Yn), 
    knight(Xn,Yn). 

%writing manually all the pairs is kinda boring 
knight_move(X,Y,Xn,Yn):- 
    alter(Ax), 
    alter(Ay,Ax), 
    Yn is Y+Ay, 
    Xn is X+Ax. 

alter(Ax):- 
    member(Ax,[1,2,-1,-2]). 
alter(Ay,Ax):- 
    Ay is 2/Ax. 
alter(Ay,Ax):- 
    Ay is -2/Ax. 

pour obtenir la liste que vous demandez simplement si chaque carré est attaqué ou non.
alors qu'il devrait prendre plus de temps pour cette application spécifique, je pense qu'il est un peu moins xd désordre aussi, si vous avez la solution nxn, vous pouvez facilement/obtenir rapidement les (n + 1) x (n + 1)

Questions connexes