Аргх !!!!!!!!

Это было непросто, несмотря на то, что я следил за лабораторными работами шаг за шагом. Ruby может быть легко понять, но выполнить его сложно!

CLI - приложения / интерфейс командной строки - это программы, с которыми вы полностью взаимодействуете через компьютерный терминал и оболочку. Нет графики, кроме той, что отображается / отображается на терминале после запуска программы. Не на что нажимать, ни папок, ни рабочего стола. Интерфейсы командной строки взаимодействуют с пользователем через вывод ASCII (числа нулей и единиц) и принимают только ввод от пользователя с тем же кодом ASCII, введенным в приглашение.

Вот что я понял из всей этой практики Ruby и CLI при создании игры:

1.) Когда дело доходит до создания кода, мы должны попытаться увидеть, что мы кодируем, с точки зрения компьютера. Все, что он видит, виртуально. По сути, мы должны построить все, от инструкций до используемых объектов. В этом случае Tic Tac Toe мы должны построить объекты - доску, жетоны, игроков, выигрышные комбинации, полную доску, связанную доску, выигрышную доску и т. Д. Затем мы должны построить инструкции. Компьютер не умеет играть в игру, поэтому мы должны научить его, как играть. Инструкции включают выигрышные комбинации, движения, повороты каждого игрока и т. Д.

2.) Они считают, начиная с 0 (нуля). Людям нравится начинать с 1 (единицы). Это жизненно важная информация.

3.) Компьютер может играть против человека. С интерфейсом командной строки это именно то; это взаимодействие человека и компьютера. Чтобы иметь такое взаимодействие, человек-пользователь должен предоставить компьютеру ввод, определяющий, что он (человек) хочет делать.

Люди:

Как мы видим крестики-нолики?

  • На доске 9 пустых квадратов.
  • Есть 2 штуки жетонов - X и O
  • Всего 2 игрока

Как мы играем в крестики-нолики?

  • Игроки по очереди играют
  • 1 ход - Игрок 1
  • Игрок 1 кладет свой жетон (X) только на 1 квадрат по своему выбору.
  • 2 ход - Игрок 2
  • Игрок 2 помещает свой жетон (O) только в 1 квадрат по своему выбору, за исключением того, что он не может коснуться квадрата, который уже заполняет жетон Игрока 1.
  • 3 ход - Игрок 1…. и цикл продолжается до тех пор, пока игрок не выиграет или не будет ничья
  • Существует 8 выигрышных комбинаций: верхний ряд, средний ряд, нижний ряд, левый столбец, средний столбец, правый столбец, левая диагональ и правая диагональ.
  • Ничья / ничья, когда вся доска заполнена крестиками и нулями, но выигрышных комбинаций не обнаружено.

Короче говоря, вышеприведенная схема и есть наш псевдокод. Написание вещей / инструкций на простом, понятном английском языке или дескрипторами может помочь нам понять, как писать код для программы.

Итак, давайте возьмем приведенный выше псевдокод и построим некоторую компьютерную логику.

CLI / Программы

Как CLI / программы видят крестики-нолики?

  • На доске 9 пустых квадратов = › Доска представляет собой массив из 9 пустых строк.

[“ ”, “ ”, “ ”, “ ”, “ ”, “ ”, “ ”, “ ”, “ ”,]

  • Есть 2 штуки жетонов - X и O = › X и O
  • Всего 2 игрока = ›Что такое игрок / Как мы определяем игрока

Как CLI / программы воспроизводят крестики-нолики?

  • Игроки играют по очереди = ›Определите, что такое ход; как игрок будет играть по очереди?
  • 1-й ход - Игрок 1…. и цикл продолжается до тех пор, пока игрок не выиграет или не будет ничья = ›итерация игры, в которой игроки по очереди; игрок не может поставить жетон на уже занятую клетку
  • Существует 8 выигрышных комбинаций: верхний ряд, средний ряд, нижний ряд, левый столбец, средний столбец, правый столбец, левая диагональ и правая диагональ = ›Определите эти комбинации
  • Ничья / ничья, когда вся доска заполнена X и O, но выигрышных комбинаций не обнаружено = ›Определите, что такое ничья / ничья; определить, что такое заполненная доска

От псевдокода к коду:

Взяв псевдокод, я начну строить свой код.

Постройте доску

Определите переменную board

puts board = [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ']

Как мы можем отобразить доску, чтобы показать, что у нас есть доска 3x3?

  • Нам нужно определить метод под названием display_board
def display_board
   puts row = ["   " "|" "   " "|" "   "]
   puts separator = "-----------"
   puts row
   puts separator
   puts row
 end
  • Доска укомплектована. Доска просматривается двумя способами - с точки зрения игроков (человека) и кода (компьютера). Мы бы отображали доску с точки зрения программы (массив, потому что программы считают, начиная с 0).
   board     (viewed by players)   (viewed by program)
   |   |          1 | 2 | 3             0 | 1 | 2
-----------      -----------           -----------
   |   |          4 | 5 | 6             3 | 4 | 5
-----------      -----------           -----------
   |   |          7 | 8 | 9             6 | 7 | 8

#board displaying the proper board[index] in its array format
def display_board(board)
   puts " #{board[0]} | #{board[1]} | #{board[2]} "
   puts "-----------"
   puts " #{board[3]} | #{board[4]} | #{board[5]} "
   puts "-----------"
   puts " #{board[6]} | #{board[7]} | #{board[8]} "
end
display_board(board)

Примечание. Мы используем строковую интерполяцию с # {board [0]}, потому что она выводит (помещает) текущее состояние доски, которое передаст метод `displayboard`.

  • Мы передадим доску каждому методу в качестве аргумента (объект в (), чтобы вспомогательные методы можно было повторно использовать в нашей логике.

Пользовательские входы

Теперь, когда доска построена, нам нужно выяснить, как пользователь выберет квадрат для ввода своих жетонов (X или O). Поскольку наша доска находится в массиве, игрок этого не узнает. Игрок начинает отсчет с 1. Когда пользователь выбирает квадрат со своей точки зрения, нам нужно преобразовать его в целое число, чтобы он мог соответствовать индексу в массиве, который видит программа. Если пользователь вводит 5 для центрального положения доски, соответствующий ему массив должен быть [4].

# To convert the user input into an integer we have to define a method to help us do that. We would use the .to_i method to change strings (which are what user inputs are) into integers, then minus 1 because the array counts up to 8, not 9.
def input_to_index(user_input)
   user_input.to_i - 1
end
  • Наша программа затем заполнит квадрат (как вид игрока) на доске преобразованным пользовательским вводом (теперь в виде целого числа минус 1) с помощью токена игрока.

Сделайте ход и подтвердите его

Теперь, когда программа считывает user_input как целое число, мы можем сказать программе сделать ход, поместив жетон игрока в этот квадрат. Начните с определения того, как перемещать фишку на доске.

def move(board, index, player)
   board[index] = player
end

Играя в эту игру, пользователь не может поставить свой жетон на уже занятую клетку. Другими словами, мы должны проверить код, чтобы убедиться, что взятый квадрат действительно пуст. Давайте определим метод, который определяет, как проверить занятую позицию.

def position_taken?(board, index)
   if (board[index] == " ") || (board[index] == "") || (board[index] == nil)
      return false 
   else
      return true
   end
end

ПРИМЕЧАНИЕ. Методы возвращают либо true, либо false, добавляя буквальный знак вопроса в конец имени метода.

Теперь мы проверяем ввод пользователя (целое число, представляющее массив доски). Если введенный пользователем номер преобразованного индекса находится между 0–8 (индекс массива) и его позиция НЕ занята, то ход действителен (истина).

def valid_move?(board, index)
   if index.between?(0,8) && !position_taken?(board, index)
      return true
   end
end

Вспомогательные методы

Если проверка позволяет пользователю / игроку разместить свой жетон, то игра может продолжаться, когда игроки по очереди играют в игру. Здесь мы создаем метод, состоящий из use of many methods (helper methods) вспомогательных методов, которые используются внутри других методов для выполнения более крупных задач, поскольку они могут использоваться повторно. Наши текущие вспомогательные методы:

display_board(board)
valid_move?(board, index)
position_taken?(board, index)
input_to_index(user_input)
move(board, index, first_player = "X")

Отслеживание поворотов

Во время игры нам нужно отслеживать, у какого игрока сейчас ход и сколько ходов было сыграно. На каждом шагу мы будем проверять, есть ли победитель.

  • Если есть победитель, они уведомляются, говоря: «X выигрывает!» или "О побед!" Если есть ничья, "Это галстук!"

Мы делаем это, определяя turn_count(board), который мы будем использовать для определения текущего playercurrent_player(board).

def turn_count(board)
   counter = 0
   board.each do |spaces|
      if spaces == "X" || spaces == "O"
         counter += 1
      end
   end
   counter
end
def current_player(board)
   turn_count(board) % 2 == 0 ? "X" : "O"
end

Время игры

Во время игры игроки играют до тех пор, пока не будет (условие). Условие, при котором есть победитель или ничья. Другими словами, мы повторяем эту игру до тех пор, пока это условие не будет выполнено. Мы начинаем игру с 0, пока не заполним 9 квадратов, или пока кто-то не выиграет или не будет ничья.

Play Method A
def play(board)
   counter = 0
   until counter == 9
     turn(board)
     counter += 1
   end
end
Play Method B
def play(board)
   until over?(board) 
      turn(board)
   end 
   if won?(board)
      winner(board) == "X" || winner(board) == "O" 
      puts "Congratulations #{winner(board)}!" 
   elsif draw?(board)
      puts "Cats Game!" 
   end 
end
#until the game is over...
#players will keep taking turns
#plays the first few turns of the game
#if there's a winner...
   #we check who the winner is...
   #and congratulate them
#if there's a draw/tie, then print the message

Метод воспроизведения А был первой итерацией этого метода. Метод воспроизведения B - это последний обновленный метод. Мы больше не считаем, что игра окончена, пока не будут заполнены все 9 квадратов. Мы считаем игру до конца, так как каждый игрок делает свою очередь. После того, как они сыграют несколько ходов, будет либо победитель, либо ничья. Если есть победитель, мы должны вызвать метод победителя (доска) и отправить сообщение.

- Метод поворота

  • Программа запрашивает у пользователя ввод
  • Пользователь вводит номер с клавиатуры; это число представляет собой строку при вводе, которую необходимо преобразовать в целое число, поскольку компьютеры / программы знают только числа. Это число будет связано с индексом массива платы минус 1.
  • Если перемещение допустимо с помощью вспомогательного метода valid_move?, поместите токен пользователя в индекс; в противном случае программа будет постоянно запрашивать у пользователя ввод, пока не будет сделан правильный ход.
  • Когда ход будет действителен, на доске отобразится вновь размещенный жетон.
def turn(board)
   puts "Please enter 1-9:"
   user_input = gets.strip
   index = input_to_index(user_input)
   if valid_move?(board, index)
      move(board, index, current_player(board))
      turn(board)
   end
   display_board(board)
end

Метод поворота turn(board) прервал мой тест, пока я работал в лаборатории. Проблема заключалась в блоке операторов if move(board, index, current_player(board)). Что я забыл о методах Ruby, так это то, что 1.) метод вызывает (или отправляет) значения, 2.) метод определен для приема значений. Мы должны думать о методах как о словаре. Словарь определяет слово и придает ему значение. Итак, когда мы определяем «слово», мы определяем «метод» в Ruby. При вызове метода или «слова» он отправляет значение. Вот как я понял оператор if, чтобы избавиться от путаницы.

метод поворота - оператор if

Оператор if turn(board) имеет 3 вспомогательных метода. Их индивидуальные определения помогут нам определить, где поставить крестик или букву O на индексе / квадрате на доске.

valid_move?(board, index)

Определение valid_move?(board, index) заключается в том, что если индекс (принимаемое значение) находится между числами 0 и 8, И его позиция на доске (принимается другое значение ) НЕ (!) сделано, тогда ход должен быть верным / действительным.

move(board, index, current_player(board))

Определение move(board, index, current_player(board)) состоит в том, что ход будет сделан после правильного хода с учетом доски, ввода пользователя index и жетона current_player.

current_player(board)

Учитывая это определение и определение двух вышеупомянутых вспомогательных методов, оператор if turn(board) говорит о том, что нужно перейти к выбранному индексу и разместить токен current_player.

Победитель? Рисовать?

  • Всего есть 8 выигрышных комбинаций:
WIN_COMBINATIONS = [ 
[0,1,2], # top_row 
[3,4,5], # middle_row 
[6,7,8], # bottom_row 
[0,3,6], # left_column 
[1,4,7], # center_column 
[2,5,8], # right_column 
[0,4,8], # left_diagonal 
[6,4,2] # right_diagonal 
]

WIN_COMBINATIONS - это константа, но это родительский массив для нашего дочернего массива. Дочерний массив содержит отдельный трехэлементный массив индексов, который сообщает нам совпадающие выигрыши [0,1,2], [3,4,5] и т. Д. Родительский массив содержит 8 элементов, каждый из которых является дочерним массивом.

parent_array => WIN_COMBINATIONS = [ children_arrays ]
children_arrays => [0,1,2],[3,4,5],[6,7,8]...[6,4,2] 

Чтобы определить победителя, мы должны получить каждый индекс родительского массива, чтобы определить победителя.

def won?(board)
 WIN_COMBINATIONS.each do |win_combination|
   win_index_1 = win_combination[0]
   win_index_2 = win_combination[1]
   win_index_3 = win_combination[2]
   position_1 = board[win_index_1] # value of board at win_index_1
   position_2 = board[win_index_2] # value of board at win_index_2
   position_3 = board[win_index_3] # value of board at win_index_3
   position_1 == position_2 && position_2 == position_3 && position_taken?(board, win_index_1)
 end
end
#position_1 == position_2 && position_2 == position_3 && position_taken?(board, win_index_1) 
The above code means to return first element (position_1) & make sure the position is taken by X or O

При определении победителя на доске отображаются крестики и нолики или пусто? Тот факт, что доска заполнена, не означает, что будет победитель. Вот выигрышный или ничейный сценарий:

  • Доска заполнена, победителя нет = ›ничья
  • Доска не заполнена, и победителя нет = ›ничья
  • Есть победитель, несмотря на то, что доска пуста или заполнена

Учитывая все это, давайте определим, что такое полный пансион (вспомогательный метод полного пансиона).

def full?(board)
   board.all? {|i| i == "X" || i == "O"}
end

Теперь определите, что такое связанная игра / доска.

def draw?(board)
   if !won?(board) && full?(board)
     return true
   elsif !won?(board) && !full?(board)
     return false
   else won?(board)
     return false
   end
end

Если игра равняется или есть победитель, давайте закончим игру.

def over?(board)
   if draw?(board) || won?(board) || full?(board)
     return true
   end
end

Объявление победителя. Когда определяется победитель, мы ищем элемент выигрышной комбинации. Если элемент имеет жетон X, победителем становится X, в противном случае - O.

def winner(board)
   if won?(board)
      return board[won?(board)[0]]
   end
end

КОНЕЦ Крестики-нолики.

** Я устал от крестиков-ноликов… -_- **

Я надеюсь, что все это кому-то понятно. Или, по крайней мере, быть полезным. Я стараюсь быть лаконичным, когда даю инструкции, описания или другую информацию, но часто говорю больше, чем следовало бы. Может быть, с кодированием и программированием, чем больше информации будет дано, тем лучше? Сейчас я лучше понимаю Ruby, тесты и интерфейс командной строки, но надеюсь вскоре прояснить это. Я просто надеюсь, что смогу применить то, что я сделал в этой статье, в будущих лабораторных работах.

Первоначально опубликовано на сайте christineiscoding.com 23 августа 2017 г.