algorithm - SWI Prolog 中的 Hangman 游戏

标签 algorithm prolog

我正在尝试在 SWI Prolog 中制作一个简单的刽子手游戏。
既然我们让这个程序运行了,你能帮我用以下方法增强这个程序吗:

1) 通过跟上目前已猜出的字母。如果用户猜了一个已经被猜到的字母,程序应该说“你猜对了!”继续游戏。

2) 最后,添加一个计数器来计算猜错的次数,并在达到一定次数时退出游戏。该程序应该告诉用户他们输了,显示该短语的真实含义,然后终止。重复猜测不应算错。

我要感谢迄今为止帮助过我的所有人。这对我来说意义重大。

我为您提供代码和注释。

% This top-level predicate runs the game.  It prints a 
% welcome message, picks a phrase, and calls getGuess.

% Ans = Answer
% AnsList = AnswerList

hangman:- 
    getPhrase(Ans), 
    !, 
    write('Welcome to hangman.'),
    nl,
    name(Ans,AnsList), 
    makeBlanks(AnsList, BlankList), 
    getGuess(AnsList,BlankList).

% Randomly returns a phrase from the list of possibilities.

getPhrase(Ans):-
    phrases(L), 
    length(L, X), 
    R is random(X), 
    N is R+1, 
    getNth(L, N, Ans).

% Possible phrases to guess.

phrases(['a_picture_is_worth_a_thousand_words','one_for_the_money','dead_or_alive','computer_science']).

% Asks the user for a letter guess.  Starts by writing the 
% current "display phrase" with blanks, then asks for a guess and
% calls process on the guess.

getGuess(AnsList, BlankList):- 
    name(BlankName, BlankList), 
    write(BlankName), 
    nl,  
    write('Enter your guess, followed by a period and return.'), 
    nl, 
    read(Guess),
    !, 
    name(Guess, [GuessName]), 
    processGuess(AnsList,BlankList,GuessName).

% Process guess takes a list of codes representing the answer, a list of codes representing the current
% "display phrase" with blanks in it, and the code of the letter that was just guessed.  If the guess
% was right, call substitute to put the letter in the display phrase and check for a win.  Otherwise, just
% get another guess from the user.

processGuess(AnsList,BlankList,GuessName):- 
    member(GuessName,AnsList), 
    !,
    write('Correct!'),
    nl, 
    substitute(AnsList, BlankList, GuessName, NewBlanks), 
    checkWin(AnsList,NewBlanks).

processGuess(AnsList, BlankList,_):-
    write('Nope!'),
    nl,
    getGuess(AnsList, BlankList).

% Check to see if the phrase is guessed.  If so, write 'You win' and if not, go back and get another guess.

checkWin(AnsList, BlankList):- 
    name(Ans, AnsList), 
    name(BlankName, BlankList), 
    BlankName = Ans, 
    !, 
    write('You win!').

checkWin(AnsList, BlankList):- 
    !,
    getGuess(AnsList, BlankList).


% getNth(L,N,E) should be true when E is the Nth element of the list L. N will always
% be at least 1.

getNth([H|T],1,H).

getNth([H|T],N,E):-
    N1 is N-1,
    getNth(T,N1,E1),
    E=E1.

% makeBlanks(AnsList, BlankList) should take an answer phrase, which is a list
% of character codes that represent the answer phrase, and return a list
% where all codes but the '_' turn into the code for '*'.  The underscores
% need to remain to show where the words start and end.  Please note that 
% both input and output lists for this predicate are lists of character codes.
% You can test your code with a query like this:
% testMakeBlanks:- name('csc_is_awesome', List), makeBlanks(List, BlankList), name(Towrite, BlankList), write(Towrite). 

makeBlanks(AnsCodes, BlankCodes) :-
  maplist(answer_blank, AnsCodes, BlankCodes).

answer_blank(Ans, Blank) :-
  Ans == 0'_ -> Blank = Ans ; Blank = 0'* .

% substitute(AnsList, BlankList, GuessName, NewBlanks) Takes character code lists AnsList and BlankList, 
% and GuessName, which is the character code for the guessed letter.  The NewBlanks should again be a 
% character code list, which puts all the guesses into the display word and keeps the *'s and _'s otherwise.
% For example, if the answer is 'csc_is_awesome' and the display is 'c*c_**_*******' and the guess is 's', the 
% new display should be 'csc_*s_***s***'.
% You can test your predicate with a query like this:
% testSubstitute:- name('csc_is_awesome', AnsList), name('c*c_**_*******', BlankList), name('s',[GuessName]), substitute(AnsList, BlankList, GuessName, NewBlanks),
%    name(Towrite, NewBlanks), write(Towrite). 

% Also, since the predicate doesn't deal directly with character codes, this should also work:
% substitute(['c','s','c'],['c','*','c'],'s',L).  L should be ['c','s','c'].

substitute(AnsCodes, BlankCodes, GuessName, NewBlanks) :-
     maplist(place_guess(GuessName), AnsCodes, BlankCodes, NewBlanks).

place_guess(Guess, Ans, Blank, Display) :-
    Guess == Ans -> Display = Ans ; Display = Blank.

最佳答案

maplist/3 & maplist/4 将他们的第一个参数(适当元数的谓词)应用于其他参数列表的所有元素,那么你的 makeBlanks 可能是:

makeBlanks(AnsCodes, BlankCodes) :-
  maplist(answer_blank, AnsCodes, BlankCodes).

answer_blank(Ans, Blank) :-
  Ans == 0'_ -> Blank = Ans ; Blank = 0'* .

和替换:

substitute(AnsCodes, BlankCodes, GuessName, NewBlanks) :-
     maplist(place_guess(GuessName), AnsCodes, BlankCodes, NewBlanks).

place_guess(Guess, Ans, Blank, Display) :-
    Guess == Ans -> Display = Ans ; Display = Blank.

编辑:

关于额外的请求:1) 可以用额外的谓词解决:

alreadyGuessed(Guess, AnsCodes) :-
   memberchk(Guess, AnsCodes).

虽然关于 2) getGuessprocessGuess 一起构成了一个循环,当没有更多的调用发生时,它就会终止。删除 checkWin 的最后一条规则,添加一个参数作为计数器以跟踪失败的猜测,并将 processGuess 扩展为失败信号:

processGuess(AnsList, BlankList, _, CountFailed) :-
  (   CountFailed == 5
  ->  format('Sorry, game over. You didn\'t guess (~s)~n', [AnsList])
  ;   write('Nope!'),
      CountFailed1 is CountFailed + 1,
      getGuess(AnsList, BlankList, CountFailed1)
  ).

关于algorithm - SWI Prolog 中的 Hangman 游戏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10743564/

相关文章:

Prolog - 什么样的句子不能表达

投影光并检测给定点是否落在其中的算法?

algorithm - 如何将机器学习应用于模糊匹配

php - iptolong是如何工作的

prolog - 以声明方式解决汉诺塔(Prolog)

prolog - DCG 惯用短语偏好

prolog - SWI-Prolog 无权限修改静态过程 `(=)/2'

javascript - 从 JavaScript 中的数组中提取最重复的值?

algorithm - 如何找出时间复杂度是指数的?

python - 来自 AllegroGraph Python API 的 Prolog 查询中的 OWL 推理