Advertisement
okrlbok

эрудит епте

Dec 14th, 2023 (edited)
119
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Delphi 19.79 KB | None | 0 0
  1. Program Scrabble;
  2.  
  3. Uses
  4.     SysUtils,
  5.     Windows;
  6.  
  7. Type
  8.     TLetterArray = Array ['а' .. 'я'] Of Integer;
  9.     TWordArray = Array Of AnsiString;
  10.     TScoreArray = Array Of Integer;
  11.     TPlayerStringArray = Array Of AnsiString;
  12.     TBonusArray = Array Of Array [0 .. 1] Of Boolean;
  13.  
  14. Const
  15.     //wb - префикс от Word Bank
  16.     WbFilePath = 'WordBank.txt';
  17.     StartLetterBank: TLetterArray = (10, 3, 4, 3, 4, 16, 4, 4, 12, 4, 4, 4, 4, 12, 16, 5, 4, 8, 8, 4, 10, 8, 2, 4, 4, 4, 4, 2, 2, 4, 5, 5);
  18.  
  19. Function CreateWordBank(): TWordArray;
  20. Var
  21.     WbSize, WbCount: Integer;
  22.     WbInputWord: AnsiString;
  23.     WbBaseFile: TextFile;
  24.     WordBank: TWordArray;
  25. Begin
  26.     WbCount := 0;
  27.     AssignFile(WbBaseFile, WbFilePath);
  28.     Reset(WbBaseFile);
  29.     Readln(WbBaseFile, WbSize);
  30.     SetLength(WordBank, WbSize);
  31.     While Not EoF(WbBaseFile) Do
  32.     Begin
  33.         Readln(WbBaseFile, WbInputWord);
  34.         WordBank[WbCount] := UTF8ToAnsi(WbInputWord);
  35.         Inc(WbCount);
  36.     End;
  37.     CloseFile(WbBaseFile);
  38.     CreateWordBank := WordBank;
  39. End;
  40.  
  41. Function InputNumberOfPlayers(): Integer;
  42. Const
  43.     MIN_NUM = 2;
  44.     MAX_NUM = 6;
  45. Var
  46.     NumOfPlayers: Integer;
  47.     IsInputCorrect: Boolean;
  48. Begin
  49.     Write('Введите количество игроков (целое число в диапазоне от 2 до 6): ');
  50.     Repeat
  51.         IsInputCorrect := True;
  52.         Try
  53.             Read(NumOfPlayers);
  54.         Except
  55.             IsInputCorrect := False;
  56.             Write('Введено недопустимое значение. Повторите ввод: ');
  57.         End;
  58.         If IsInputCorrect And ((NumOfPlayers < MIN_NUM) Or (NumOfPlayers > MAX_NUM)) Then
  59.         Begin
  60.             IsInputCorrect := False;
  61.             Write('Введено число, не входящее в диапазон допустимых значений. Повторите ввод: ');
  62.         End;
  63.     Until IsInputCorrect;
  64.     InputNumberOfPlayers := NumOfPlayers;
  65. End;
  66.  
  67. Function CheckLetterCount(PlayerString: String; LetterBank: TLetterArray): Boolean;
  68. Var
  69.     MissingLetters, LetterCounter: Integer;
  70.     I: AnsiChar;
  71.     IsEnough: Boolean;
  72. Begin
  73.     IsEnough := True;
  74.     MissingLetters := 10 - Length(PlayerString);
  75.     LetterCounter := 0;
  76.     For I := 'а' To 'я' Do
  77.         LetterCounter := LetterCounter + LetterBank[I];
  78.     If MissingLetters > LetterCounter Then
  79.         IsEnough := False;
  80.     CheckLetterCount := IsEnough;
  81. End;
  82.  
  83. Procedure FillPlayerString(Var TempPlayerString: AnsiString; Var LetterBank: TLetterArray);
  84. Var
  85.     RandomLetter: AnsiChar;
  86.     RandomIndex, CountOfLetter: Integer;
  87. Begin
  88.     Randomize;
  89.     While (Length(TempPlayerString) < 10) Do //Нужно набрать 10 букв
  90.     Begin
  91.         RandomIndex := Random(32) + 224;
  92.         RandomLetter := AnsiChar(RandomIndex);
  93.         CountOfLetter := LetterBank[RandomLetter];
  94.         If CountOfLetter > 0 Then
  95.         Begin
  96.             TempPlayerString := TempPlayerString + RandomLetter;
  97.             Dec(LetterBank[RandomLetter]);
  98.         End;
  99.     End;
  100. End;
  101.  
  102. Function ReadPlayersWord(Var LetterPack: AnsiString): AnsiString;
  103. Const
  104.     RUS_LETTERS = ['а' .. 'я'];
  105.     MAX_LENGTH = 10;
  106.     MOVE_SKIP = '';
  107.     FIFTY_FIFTY = '50';
  108.     FRIEND_HELP = '+';
  109. Var
  110.     CharCount, LetterCount, FoundLetters: Integer;
  111.     InputWord, StartPack: AnsiString;
  112.     IsInputCorrect: Boolean;
  113. Begin
  114.     StartPack := LetterPack;
  115.     Repeat
  116.         Readln(InputWord);
  117.         If (InputWord = '') Then
  118.             Read(InputWord);
  119.         IsInputCorrect := True;
  120.         Trim(InputWord);
  121.         If (InputWord <> FIFTY_FIFTY) And (InputWord <> FRIEND_HELP) And (InputWord <> MOVE_SKIP) Then
  122.         Begin
  123.             For CharCount := 1 To Length(InputWord) Do
  124.                 If Not(InputWord[CharCount] In RUS_LETTERS) Then
  125.                     IsInputCorrect := False;
  126.             If Not IsInputCorrect Or (Length(InputWord) > MAX_LENGTH) Then
  127.                 Write('Слово введено некорректно. Повторите ввод: ')
  128.             Else
  129.             Begin
  130.                 FoundLetters := 0;
  131.                 For CharCount := 1 To Length(InputWord) Do
  132.                 Begin
  133.                     For LetterCount := 1 To High(LetterPack) Do
  134.                         If (InputWord[CharCount] = LetterPack[LetterCount]) And (LetterPack[LetterCount] <> '0') Then
  135.                         Begin
  136.                             Inc(FoundLetters);
  137.                             LetterPack[LetterCount] := '0';
  138.                             Break;
  139.                         End;
  140.                 End;
  141.                 If (FoundLetters <> Length(InputWord)) Then
  142.                 Begin
  143.                     IsInputCorrect := False;
  144.                     Write('Введено слово, не соответствующее условию игры. Повторите ввод: ');
  145.                     LetterPack := StartPack;
  146.                 End;
  147.             End;
  148.         End;
  149.     Until IsInputCorrect;
  150.     ReadPlayersWord := InputWord;
  151. End;
  152.  
  153. Function IsWordInBank(ExpectedWord: String; WordBank: TWordArray): Boolean;
  154. Var
  155.     LeftIndex, RightIndex, MiddleIndex: Integer;
  156.     IsFound: Boolean;
  157. Begin
  158.     LeftIndex := 0;
  159.     IsFound := False;
  160.     RightIndex := High(WordBank);
  161.     While (LeftIndex <= RightIndex) And (IsFound = False) Do
  162.     Begin
  163.         MiddleIndex := (LeftIndex + RightIndex) Div 2;
  164.         If WordBank[MiddleIndex] = ExpectedWord Then
  165.             IsFound := True
  166.         Else
  167.         Begin
  168.             If WordBank[MiddleIndex] < ExpectedWord Then
  169.                 LeftIndex := MiddleIndex + 1
  170.             Else
  171.                 RightIndex := MiddleIndex - 1;
  172.         End;
  173.     End;
  174.     IsWordInBank := IsFound;
  175. End;
  176.  
  177. //процедура очистки консоли, честно спизжена с просторов интернета
  178. Procedure ClearConsole();
  179. Var
  180.     HStdOut: HWND;
  181.     ScreenBufInfo: TConsoleScreenBufferInfo;
  182.     Coord1: TCoord;
  183.     Z: Integer;
  184. Begin
  185.     HStdOut := GetStdHandle(STD_OUTPUT_HANDLE);
  186.     GetConsoleScreenBufferInfo(HStdOut, ScreenBufInfo);
  187.     For Z := 1 To ScreenBufInfo.DwSize.Y Do
  188.         WriteLn;
  189.     Coord1.X := 0;
  190.     Coord1.Y := 0;
  191.     SetConsoleCursorPosition(HStdOut, Coord1);
  192. End;
  193.  
  194. Procedure OutputMoveConditions(PlayerCount: Integer; LetterPack: AnsiString);
  195. Var
  196.     LetterCount: Integer;
  197. Begin
  198.     ClearConsole();
  199.     Writeln('Ход игрока ', PlayerCount + 1, '.', #13#10);
  200.     Writeln('Нажмите Enter, если вы хотите пропустить ход.');
  201.     Writeln('Введите 50, если вы хотите использовать бонус "50/50".');
  202.     Writeln('Введите +, если вы хотите использовать бонус "Помощь друга".', #13#10);
  203.     Write('Ваш набор букв: [');
  204.     //чуть более читаемый вывод набора букв
  205.     For LetterCount := 1 To 9 Do
  206.         Write(LetterPack[LetterCount], ', ');
  207.     Writeln(LetterPack[10], ']', #13#10);
  208.     Write('Введите ваше слово: ');
  209. End;
  210.  
  211. Function ResultOfVote(PlayerCount, NumberOfPlayers: Integer): Boolean;
  212. Const
  213.     VOTE_FOR = 'ДА';
  214.     VOTE_AGAINST = 'НЕТ';
  215. Var
  216.     VoteCount, VotesFor, MinAmountOfVotes: Integer;
  217.     Vote: AnsiString;
  218.     IsInputCorrect, IsVotedFor: Boolean;
  219. Begin
  220.     Writeln('Введите ДА, чтобы проголосовать за, и НЕТ, чтобы проголосовать против.', #13#10);
  221.     MinAmountOfVotes := NumberOfPlayers Div 2 + NumberOfPlayers Mod 2;
  222.     VotesFor := 1;
  223.     Dec(NumberOfPlayers);
  224.     For VoteCount := 0 To NumberOfPlayers Do
  225.     Begin
  226.         If (VoteCount <> PlayerCount) Then
  227.         Begin
  228.             Write('Игрок ', VoteCount + 1, ', ваш голос: ');
  229.             Repeat
  230.                 IsInputCorrect := True;
  231.                 Readln(Vote);
  232.                 If (Vote = '') Then
  233.                     Read(Vote);
  234.                 If (Vote <> VOTE_FOR) And (Vote <> VOTE_AGAINST) Then
  235.                 Begin
  236.                     IsInputCorrect := False;
  237.                     Write('Введено некорректное значение. Повторите ввод: ');
  238.                 End;
  239.             Until IsInputCorrect;
  240.             If (Vote = VOTE_FOR) Then
  241.                 Inc(VotesFor);
  242.         End;
  243.     End;
  244.     If (VotesFor >= MinAmountOfVotes) Then
  245.         IsVotedFor := True
  246.     Else
  247.         IsVotedFor := False;
  248.     ResultOfVote := IsVotedFor;
  249. End;
  250.  
  251. Function ExecuteBonus50(Var PlayerString: AnsiString; LetterBank: TLetterArray; PlayersScore: TScoreArray; NumberOfPlayer: Integer)
  252.   : Boolean;
  253. Var
  254.     CountLetters, CountChar, ChangeIndex: Integer;
  255.     IsCorrect, IsOkay: Boolean;
  256.     C: Char;
  257.     LettertoChange: AnsiString;
  258.     PlayersCopy: AnsiString;
  259. Begin
  260.     Randomize;
  261.     PlayersCopy := PlayerString;
  262.     For CountLetters := 0 To 4 Do
  263.         Repeat
  264.             Writeln('Введите букву из вашего набора, которую хотели бы заменить: ');
  265.             Readln(LetterToChange);
  266.             If (LetterToChange = #13) Then
  267.                 Readln(LetterToChange
  268.                 );
  269.             IsCorrect := False;
  270.             For CountChar := 1 To 10 Do
  271.                 If (LetterToChange = PlayersCopy[CountChar]) Then
  272.                 Begin
  273.                     IsCorrect := True;
  274.                     PlayersCopy[CountChar] := '0';
  275.                     Repeat
  276.                         IsOkay := True;
  277.                         ChangeIndex := 255 - Random(32);
  278.                         If (LetterBank[AnsiChar(ChangeIndex)] < 1) Then
  279.                             IsOkay := False;
  280.                     Until (IsOkay);
  281.                     Dec(LetterBank[AnsiChar(ChangeIndex)]);
  282.                     PlayerString[CountChar] := AnsiChar(ChangeIndex);
  283.                     Break;
  284.                 End;
  285.             If Not(IsCorrect) Then
  286.                 Writeln('В вашем наборе отсутствует такая буква или встречается меньшее количество раз. Повторите ввод');
  287.         Until (IsCorrect);
  288.     Dec(PlayersScore[NumberOfPlayer], 2);
  289.     ExecuteBonus50 := True;
  290. End;
  291.  
  292. Function CheckIfContains(PlayerString: AnsiString; Var LetterIndex: Integer; NumberOfPlayer: Integer): AnsiChar;
  293. Var
  294.     LetterCounter: Integer;
  295.     Letter: AnsiChar;
  296.     IsCorrect: Boolean;
  297. Begin
  298.     Repeat
  299.         Readln(Letter);
  300.         If (Letter = #13) Then
  301.             Readln(Letter);
  302.         IsCorrect := False;
  303.         For LetterCounter := 1 To 10 Do
  304.             If (Letter = PlayerString[LetterCounter]) Then
  305.             Begin
  306.                 IsCorrect := True;
  307.                 LetterIndex := LetterCounter;
  308.             End;
  309.         If Not(IsCorrect) Then
  310.             Writeln('В наборе отсутствует такая буква. Повторите ввод: ');
  311.     Until (IsCorrect);
  312.     CheckIfContains := Letter;
  313. End;
  314.  
  315. Function ExecuteBonusHelp(PlayersLetters: TPlayerStringArray; NumberOfPlayer: Integer): Boolean;
  316. Var
  317.     IsCorrect: Boolean;
  318.     LetterToChange, DesiredLetter: AnsiChar;
  319.     LetterIndexToChange, DesiredLetterIndex, OtherPlayerNumber: Integer;
  320. Begin
  321.     Writeln('Введите букву из вашего набора, которую хотели бы заменить: ');
  322.     LetterToChange := CheckIfContains(PlayersLetters[NumberOfPlayer], LetterIndexToChange, NumberOfPlayer);
  323.     Writeln('Введите номер игрока, с которым хотели бы обменяться: ');
  324.     Repeat
  325.         Readln(OtherPlayerNumber);
  326.         IsCorrect := True;
  327.         Dec(OtherPlayerNumber);
  328.         If (OtherPlayerNumber = NumberOfPlayer) Then
  329.         Begin
  330.             Writeln('Вы не можете меняться с самим собой. Повторите ввод:');
  331.             IsCorrect := False;
  332.         End;
  333.         If (OtherPlayerNumber > High(PlayersLetters)) Then
  334.         Begin
  335.             Writeln('Такого игрока не существует. Повторите ввод');
  336.             IsCorrect := False;
  337.         End;
  338.     Until (IsCorrect);
  339.     Writeln('Введите букву из чужого набора, на которую хотели бы заменить');
  340.     DesiredLetter := CheckIfContains(PlayersLetters[OtherPlayerNumber], DesiredLetterIndex, OtherPlayerNumber);
  341.     PlayersLetters[NumberOfPlayer, LetterIndexToChange] := DesiredLetter;
  342.     PlayersLetters[OtherPlayerNumber, DesiredLetterIndex] := LetterToChange;
  343.     ExecuteBonusHelp := True;
  344. End;
  345.  
  346. Procedure PlayGame(Var WordBank: TWordArray; Var NumberOfPlayers: Integer; Var PlayersScore: TScoreArray; BonusUsageArray: TBonusArray);
  347. Const
  348.     MOVE_SKIP = '';
  349.     FIFTY_FIFTY = '50';
  350.     FRIEND_HELP = '+';
  351. Var
  352.     LastLetter: AnsiChar;
  353.     PlayerCount, SkippedMoves, HelpCount, HelpHelpCount, RandomIndex: Integer;
  354.     IsWordCorrect, IsVotedFor, IsGameOver: Boolean;
  355.     InputWord: AnsiString;
  356.     LetterBank: TLetterArray;
  357.     PlayersLetters: TPlayerStringArray;
  358. Begin
  359.     Randomize;
  360.     LastLetter := #0;
  361.     InputWord := '';
  362.     SetLength(PlayersLetters, NumberOfPlayers);
  363.     SetLength(PlayersScore, NumberOfPlayers);
  364.     SetLength(BonusUsageArray, NumberOfPlayers);
  365.     LetterBank := StartLetterBank;
  366.     IsGameOver := False;
  367.     Repeat
  368.         SkippedMoves := 0;
  369.         //заполняются наборы букв
  370.         For PlayerCount := 0 To High(PlayersLetters) Do
  371.             FillPlayerString(PlayersLetters[PlayerCount], LetterBank);
  372.         //цикл ходов игроков в рамках одного хода игры
  373.         For PlayerCount := 0 To High(PlayersScore) Do
  374.         Begin
  375.             For HelpCount := 0 To High(PlayersLetters) Do
  376.                 For HelpHelpCount := 1 To Length(PlayersLetters[HelpCount]) Do
  377.                     If (PlayersLetters[HelpCount][HelpHelpCount] = '0') Then
  378.                     Begin
  379.                         RandomIndex := Random(32) + 224;
  380.                         PlayersLetters[HelpCount][HelpHelpCount] := AnsiChar(RandomIndex);
  381.                     End;
  382.             OutputMoveConditions(PlayerCount, PlayersLetters[PlayerCount]);
  383.             InputWord := ReadPlayersWord(PlayersLetters[PlayerCount]);
  384.             If (InputWord = MOVE_SKIP) Then
  385.                 Inc(SkippedMoves)
  386.             Else
  387.             Begin
  388.                 If (InputWord = FIFTY_FIFTY) Then
  389.                 Begin
  390.                     If (BonusUsageArray[PlayerCount, 0]) Then
  391.                         Writeln('Вы уже использовали этот бонус.')
  392.                     Else
  393.                         BonusUsageArray[PlayerCount, 0] := ExecuteBonus50(PlayersLetters[PlayerCount], LetterBank, PlayersScore,
  394.                           PlayerCount);
  395.                 End
  396.                 Else
  397.                 Begin
  398.                     If (InputWord = FRIEND_HELP) Then
  399.                     Begin
  400.                         If (BonusUsageArray[PlayerCount, 0]) Then
  401.                             Writeln('Вы уже использовали этот бонус.')
  402.                         Else
  403.                         Begin
  404.                             For HelpCount := 0 To High(PlayersLetters) Do
  405.                                 If (HelpCount <> PlayerCount) Then
  406.                                     Writeln('Набор игрока ', HelpCount + 1, ': [', PlayersLetters[HelpCount], '].');
  407.                             BonusUsageArray[PlayerCount, 1] := ExecuteBonusHelp(PlayersLetters, PlayerCount);
  408.                         End;
  409.                     End
  410.                     Else
  411.                     Begin
  412.                         IsWordCorrect := IsWordInBank(InputWord, WordBank);
  413.                         If IsWordCorrect Then
  414.                         Begin
  415.                             If (InputWord[1] = LastLetter) Then
  416.                                 PlayersScore[PlayerCount] := 2 * (PlayersScore[PlayerCount] + Length(InputWord))
  417.                             Else
  418.                                 PlayersScore[PlayerCount] := PlayersScore[PlayerCount] + Length(InputWord);
  419.                             Writeln(#13#10, 'Слово верное! Ваш счёт: ', PlayersScore[PlayerCount]);
  420.                         End
  421.                         Else
  422.                         Begin
  423.                             Writeln(#13#10, 'Голосование: добавлять ли слово "', InputWord, '" в Банк Слов?');
  424.                             IsVotedFor := ResultOfVote(PlayerCount, Length(PlayersScore));
  425.                             If IsVotedFor Then
  426.                             Begin
  427.                                 If (InputWord[1] = LastLetter) Then
  428.                                     PlayersScore[PlayerCount] := 2 * (PlayersScore[PlayerCount] + Length(InputWord))
  429.                                 Else
  430.                                     PlayersScore[PlayerCount] := PlayersScore[PlayerCount] + Length(InputWord);
  431.                                 //сюда вставить функцию добавления слова в Банк Букв
  432.                                 Writeln(#13#10, 'Слово внесено в Банк Слов! Ваш счёт: ', PlayersScore[PlayerCount]);
  433.                             End
  434.                             Else
  435.                             Begin
  436.                                 PlayersScore[PlayerCount] := PlayersScore[PlayerCount] + (-1) * Length(InputWord);
  437.                                 Writeln(#13#10, 'Слово не внесено в Банк Слов. Ваш счёт: ', PlayersScore[PlayerCount]);
  438.                             End;
  439.                         End;
  440.                     End;
  441.                 End;
  442.                 Writeln(#13#10, 'Нажмите Enter, чтобы перейти к следующему ходу.');
  443.                 Readln;
  444.                 //такие убогие условия иногда встречаются, какая-то проблема с самым первым считыванием
  445.                 If (LastLetter = #0) Then
  446.                     Readln;
  447.                 LastLetter := InputWord[Length(InputWord)];
  448.             End;
  449.         End;
  450.         If (SkippedMoves = Length(PlayersScore)) Then
  451.             IsGameOver := True;
  452.         If (SkippedMoves = Length(PlayersScore)) And (LastLetter = #0) Then
  453.             NumberOfPlayers := -1;
  454.     Until IsGameOver;
  455. End;
  456.  
  457. Procedure FindWinner(AmountOfPlayers: Integer; Var PlayerScore: TScoreArray);
  458. Var
  459.     NumberOfPlayer, Max, WinnerNumber: Integer;
  460. Begin
  461.     ClearConsole;
  462.     If (AmountOfPlayers <> -1) Then
  463.     Begin
  464.         Max := PlayerScore[0];
  465.         WinnerNumber := 0;
  466.         For NumberOfPlayer := 1 To High(PlayerScore) Do
  467.         Begin
  468.             If PlayerScore[NumberOfPlayer] > Max Then
  469.             Begin
  470.                 Max := PlayerScore[NumberOfPlayer];
  471.                 WinnerNumber := NumberOfPlayer;
  472.             End;
  473.         End;
  474.         Writeln('Игра завершена! Победитель - игрок под номером ', WinnerNumber + 1, ' со счётом ', Max, '.');
  475.         Writeln(#13#10, 'Поздравляем!', #13#10, #13#10, 'Нажмите Enter, чтобы выйти из игры.');
  476.     End
  477.     Else
  478.     Begin
  479.         Writeln('Не было сделано ни одного хода. Игра завершена.');
  480.         Writeln(#13#10, 'Нажмите Enter, чтобы выйти из игры.');
  481.     End;
  482.     Readln;
  483. End;
  484.  
  485. Var
  486.     WordBank: TWordArray;
  487.     NumberOfPlayers: Integer;
  488.     PlayersScore: TScoreArray;
  489.     BonusUsageArray: TBonusArray;
  490.  
  491. Begin
  492.     WordBank := CreateWordBank();
  493.     NumberOfPlayers := InputNumberOfPlayers();
  494.     PlayGame(WordBank, NumberOfPlayers, PlayersScore, BonusUsageArray);
  495.     FindWinner(NumberOfPlayers, PlayersScore);
  496.     Readln;
  497.  
  498. End.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement