1

我用许多编程语言编写了很多东西,而 Prolog 不是这些语言中的一种。我应该编写一个程序,当给定一个谜题表示作为输入时,它将解决数独谜题。

我的想法:
将所有提供的数字存储在列表列表(行列表)中,并强制使用可能的选项,直到合适为止(我知道,这不是最优雅的,但我没有太多时间花在写作上找出以常规方式解决难题的逻辑)。但是,作为 Prolog 的新手,我很难理解做事的方式。输入在文本文件中以行的形式给出,如下所示

1-2---34-
-34--1-5-

等等等等。我读取和打印文件的代码是:

readPuzzle(File) :-
  see(File),
  repeat,
  get_char(X),
  (X = end_of_file, !
   ;
   write(X),
   fail
  ),
  seen.

这一切都很好。所以假设我尝试通过W = [] 在上面添加一个see(File)并替换write(X)为来构建这个列表W = [W|X]。根据我的经验,这应该会创建一个包含从文本文件提供的所有字符的长列表。
它没有。有人请要么

  • 告诉我一个更好的更顺理成章的方式来完成我面前的任务
  • 解释我如何解决这个问题。
4

2 回答 2

2

我会编写一个描述谜题语法的 DCG,然后使用 library(pio) 来使用 DCG 从文件中读取谜题。例如:

:- use_module(library(pio)).

puzzle([Line|Lines]) -->
        line(Line),
        !,
        puzzle(Lines).
puzzle([]) --> [].

line([]) --> "\n".
line([_|Ls]) --> "-", !, line(Ls).
line([N|Ls]) --> [D], { name(N, [D]) }, line(Ls).

当我将您的示例拼图保存在文件“sud.txt”中时,我得到:

?- phrase_from_file(puzzle(Ps), 'sud.txt'), maplist(writeln, Ps).
[1,_G517,2,_G526,_G529,_G532,3,4,_G547]
[_G553,3,4,_G568,_G571,1,_G580,5,_G589]
Ps = [[1, _G517, 2, _G526, _G529, _G532, 3, 4|...], [_G553, 3, 4, _G568, _G571, 1, _G580|...]].
于 2012-04-27T21:10:39.063 回答
1

有几种方法可以完成规范阅读。如果您愿意重用您的代码,我建议使用 assertz:

:- dynamic onechar/1.

readPuzzle(File) :-
  see(File),
  repeat,
  get_char(X),
  (X = end_of_file, !
   ;
   asssertz(onechar(X)), % write(X),
   fail
  ),
  seen.

并使用

 ...,  findall(L, retract(onechar(C)), Cs), ...

要读取字符列表,则需要将列表拆分为行,丢弃行的分隔符。

否则,我们可以使用服务谓词来收集更多结构化输入和约束长度,而不是断言/撤回:

readPuzzle(File, Puzzle) :-
  see(File),
  length(Puzzle, 9),  % this allocates a list of unbound variables
  maplist(read_a_line, Puzzle),
  seen.

read_a_line(Line) :-
  length(Line, 9),
  maplist(get_char, Line),
  get_char(_). % get rid of nl

有关如何在 SWI-Prolog 中工作的示例:

?- length(L,9),see(user),maplist(get,L),seen.
|: 987654321

L = [57, 56, 55, 54, 53, 52, 51, 50, 49].

更新

这是另一种方式,使用累加器来收集结构化输入和大小。

readPuzzle(File, Puzzle, Length) :-
  see(File),
  readLines([], 0, Puzzle, Length),
  seen.

readLines(SoFar, CountSoFar, Lines, CountLines) :-
  get_char(C), % lookahead
  C \= end_of_file,
  readLine(C, [], Line),
  M is SoFar + 1,
  readLines([Line|SoFar], M, Lines, CountLines).
readLines(Lines, TotLines, Lines, TotLines).

readLine(C, Line, Line) :-
 C == 10.
readLine(C, SoFar, Line) :-
 get_char(S),
 readLine(S, [C|SoFar], Line).
于 2012-04-27T05:49:13.090 回答