Hướng dẫn tic-tac-toe oop python - tic-tac-toe oop con trăn

Hướng dẫn tic-tac-toe oop python - tic-tac-toe oop con trăn

Dự án Tic-tac-toe được viết bằng Python. Tệp dự án chứa tập lệnh python (main.py). Chương trình này thực hiện trò chơi cho hai người chơi. Tất cả các quy tắc chơi đều giống như chúng ta chơi trong thời gian thực tic-tac-toe. Đây là một trò chơi hai người chơi đơn giản.

Về dự án

Trò chơi này chỉ đơn giản là trong dòng lệnh. Đầu tiên, người chơi phải chọn giữa ‘o’ hoặc ‘x’ để bắt đầu trò chơi. Bạn phải gõ từ 1 đến 9 để đặt giá trị vào ô trò chơi. Thiết kế lối chơi rất đơn giản nên người dùng sẽ không cảm thấy khó khăn khi sử dụng và hiểu.

Làm thế nào để chạy dự án?

Để chạy dự án này, bạn phải cài đặt  Python  trên PC của mình. Sau khi tải xuống dự án, hãy làm theo các bước dưới đây:

Bước 1:  Giải nén / Giải nén tệp  Giải nén / Giải nén tệp

Bước 2: Vào  bên trong thư mục dự án, mở cmd sau đó gõ main.py và enter để khởi động hệ thống.  bên trong thư mục dự án, mở cmd sau đó gõ main.py và enter để khởi động hệ thống.

HOẶC LÀ

Bước 2:  Chỉ cần nhấp đúp vào tệp main.py và bạn đã sẵn sàng.  Chỉ cần nhấp đúp vào tệp main.py và bạn đã sẵn sàng.

Đây là một hệ thống dựa trên cmd đơn giản, được viết đặc biệt cho người mới bắt đầu. Dự án này bằng Python với mã nguồn được tải xuống miễn phí. Chỉ sử dụng cho mục đích giáo dục! Chỉ sử dụng cho mục đích giáo dục!

Bản thương mại nhiều người tải nhất

Hãy lựa chọn cho minh project phù hợp nhất, ngoài sản phẩm free , dự án trả phí bạn mua nó về sử dụng khám phá nhiều cái mới lạ


Hướng dẫn tic-tac-toe oop python - tic-tac-toe oop con trăn

Dự án trò chơi này được viết bằng Python. Tệp dự án chứa tập lệnh python (TicTacToe.py). Đây là một trò chơi hội đồng chiến lược dựa trên GUI đơn giản, rất dễ hiểu và dễ sử dụng. Tất cả các quy tắc chơi đều giống như chúng ta chơi trong thời gian thực tic-tac-toe. Đây là một trò chơi nhiều người chơi đơn giản.

Về dự án

Trò chơi Tic Tac Toe bắt đầu với một bảng GUI. Đầu tiên, người chơi phải nhấp vào ô bất kỳ để bắt đầu trò chơi. Nó chứa thuật toán Minimax; là quy tắc quyết định được sử dụng cho trò chơi hai người chơi. Giao diện đồ họa 2D đơn giản được cung cấp để dễ dàng chơi game. Thiết kế lối chơi rất đơn giản nên người dùng sẽ không cảm thấy khó khăn khi sử dụng và hiểu.

Làm thế nào để chạy dự án?

Để chạy dự án này, bạn phải cài đặt  Python  trên PC của mình. Sau khi tải xuống dự án, hãy làm theo các bước dưới đây:

Bước 1:  Giải nén / Giải nén tệp  Giải nén / Giải nén tệp

Bước 2: Vào  bên trong thư mục dự án, mở cmd sau đó gõ TicTacToe.py và enter để khởi động hệ thống.  bên trong thư mục dự án, mở cmd sau đó gõ TicTacToe.py và enter để khởi động hệ thống.

HOẶC LÀ

Bước 2:  Chỉ cần nhấp đúp vào tệp TicTacToe.py và bạn đã sẵn sàng.  Chỉ cần nhấp đúp vào tệp TicTacToe.py và bạn đã sẵn sàng.

Đây là một hệ thống dựa trên GUI đơn giản, được viết đặc biệt cho người mới bắt đầu. Tic Tac Toe trong dự án Python với mã nguồn được tải xuống miễn phí


Chuyện là khi mình nghịch Ruby contest ở trang codingame, mình tìm thấy 1 bài toán khá thú vị, đó là tạo game TicTacToe (cờ caro 3x3) bằng code Ruby.

Link bài học : https://www.codingame.com/playgrounds/46635/tic-tac-toe-game-implementation

Ở trong link bên trên đã có sẵn phần description và sourecode của bài toán này. Phần sourecode khá ngắn, chỉ có 116 dòng . Và bạn có thể test sourecode khá đơn giản với trình thông dịch Ruby(irb) trong

 X |   | X   
-----------
   | X |    
-----------
 O | O | O  
=> Congratulations O!
7 của bạn (điều kiện là máy tính của bạn đã cài Ruby) .

Game cờ caro 3x3(

 X |   | X   
-----------
   | X |    
-----------
 O | O | O  
=> Congratulations O!
8 ) mà bạn có thể tưởng tượng ra là như thế này:
Hướng dẫn tic-tac-toe oop python - tic-tac-toe oop con trăn
) . (part 2)

Okay, giờ thì bắt đầu thoai.

1. Game TicTacToe chơi như thế nào?

Để chơi game, đầu tiên chúng ta cần một bảng 3x3 ô trống như thế này, tạm gọi là

 X | O | X   
-----------
 O | X | O   
-----------
 O | X | O  
=> Cat's game
3 .

irb(main):118:0> TicTacToe.new.display_board
   |   |   
-----------
   |   |   
-----------
   |   |   

Sẽ chỉ có 2 players, mỗi player tương ứng với 1

 X | O | X   
-----------
 O | X | O   
-----------
 O | X | O  
=> Cat's game
4 để điền vào
 X | O | X   
-----------
 O | X | O   
-----------
 O | X | O  
=> Cat's game
3 là
 X | O | X   
-----------
 O | X | O   
-----------
 O | X | O  
=> Cat's game
6 hoặc
 X | O | X   
-----------
 O | X | O   
-----------
 O | X | O  
=> Cat's game
7 . Ở đây ta quy ước như sau:

  • Player 1 tương ứng với
     X | O | X   
    -----------
     O | X | O   
    -----------
     O | X | O  
    => Cat's game
    
    6
  • Player 2 tương ứng với
     X | O | X   
    -----------
     O | X | O   
    -----------
     O | X | O  
    => Cat's game
    
    7 2 players sẽ chơi theo lượt ,
    class TicTacToe
      attr_reader :board
      WIN_COMBINATIONS = [
        [0,1,2],
        [3,4,5],
        [6,7,8],
        [0,3,6],
        [1,4,7],
        [2,5,8],
        [0,4,8],
        [2,4,6]
      ]
    
      def initialize(board = nil, options = {})
        @options = {rows: 3, cols: 3, chr_empty: ' ', chr_separ_v: '|', chr_separ_h: '-', players: {'Player 1': 'X', 'Player 2': 'O'}}
        @options = @options.merge(options)
        @board = board || Array.new(self.cells_count, @options[:chr_empty])
      end
    
      def cells_count
        @options[:rows]*@options[:cols]
      end
    
      def get_cell_from_row_col(row, col)
        # puts "row: #{row}, col: #{col}, cell: #{((row-1)*@options[:cols])+col-1}"
        @board[((row-1)*@options[:cols])+col-1]
      end
    
      def display_board
        @options[:rows].times.with_index(1) do |r, row_index|
          str_row = ''
          @options[:cols].times.with_index(1) do |c, col_index|
            str_row += @options[:chr_empty]+get_cell_from_row_col(row_index, col_index)+@options[:chr_empty]
            str_row += @options[:chr_separ_v] if col_index < @options[:cols]
          end
          puts str_row
          puts @options[:chr_separ_h]*((@options[:cols]*3)+@options[:cols]-1) if row_index < @options[:rows]
        end
      end
    
      def input_to_index(str_input)
        str_input.to_i-1
      end
    
      def move(index, player_token)
        @board[index] = player_token
      end
    
      def position_taken?(index)
        !@board[index].strip.empty?
      end
    
      def valid_move?(index)
        index.between?(0, cells_count-1) && !position_taken?(index)
      end
    
      def turn
        puts "Enter position (1-9):"
        index = input_to_index(gets.strip)
        if valid_move?(index)
          move(index, current_player)
          display_board
        else
          turn
        end
      end
    
      def turn_count
        counter = 0
        @board.each {|cell| counter += 1 unless cell.strip.empty?}
        counter
      end
    
      def current_player
        turn_count % 2 == 0 ? 'X' : 'O'
      end
    
      def won?
        ret = nil
        WIN_COMBINATIONS.each do |wc|
          if wc.all? { |index| position_taken?(index) && @board[index] == @board[wc[0]]}
            ret = wc
            break
          end
        end
        ret
      end
    
      def full?
        turn_count == cells_count
      end
    
      def draw?
        full? && !won?
      end
    
      def over?
        won? || full?
      end
    
      def winner
        won = won?
        won ? @board[won[0]] : nil
      end
    
      def play
        until over? do
          turn
        end
        if won?
          puts "Congratulations #{winner}!"
        else
          puts "Cat's Game!"
        end
      end
    end
    
    0 sẽ chơi lượt lẻ,
    class TicTacToe
      attr_reader :board
      WIN_COMBINATIONS = [
        [0,1,2],
        [3,4,5],
        [6,7,8],
        [0,3,6],
        [1,4,7],
        [2,5,8],
        [0,4,8],
        [2,4,6]
      ]
    
      def initialize(board = nil, options = {})
        @options = {rows: 3, cols: 3, chr_empty: ' ', chr_separ_v: '|', chr_separ_h: '-', players: {'Player 1': 'X', 'Player 2': 'O'}}
        @options = @options.merge(options)
        @board = board || Array.new(self.cells_count, @options[:chr_empty])
      end
    
      def cells_count
        @options[:rows]*@options[:cols]
      end
    
      def get_cell_from_row_col(row, col)
        # puts "row: #{row}, col: #{col}, cell: #{((row-1)*@options[:cols])+col-1}"
        @board[((row-1)*@options[:cols])+col-1]
      end
    
      def display_board
        @options[:rows].times.with_index(1) do |r, row_index|
          str_row = ''
          @options[:cols].times.with_index(1) do |c, col_index|
            str_row += @options[:chr_empty]+get_cell_from_row_col(row_index, col_index)+@options[:chr_empty]
            str_row += @options[:chr_separ_v] if col_index < @options[:cols]
          end
          puts str_row
          puts @options[:chr_separ_h]*((@options[:cols]*3)+@options[:cols]-1) if row_index < @options[:rows]
        end
      end
    
      def input_to_index(str_input)
        str_input.to_i-1
      end
    
      def move(index, player_token)
        @board[index] = player_token
      end
    
      def position_taken?(index)
        !@board[index].strip.empty?
      end
    
      def valid_move?(index)
        index.between?(0, cells_count-1) && !position_taken?(index)
      end
    
      def turn
        puts "Enter position (1-9):"
        index = input_to_index(gets.strip)
        if valid_move?(index)
          move(index, current_player)
          display_board
        else
          turn
        end
      end
    
      def turn_count
        counter = 0
        @board.each {|cell| counter += 1 unless cell.strip.empty?}
        counter
      end
    
      def current_player
        turn_count % 2 == 0 ? 'X' : 'O'
      end
    
      def won?
        ret = nil
        WIN_COMBINATIONS.each do |wc|
          if wc.all? { |index| position_taken?(index) && @board[index] == @board[wc[0]]}
            ret = wc
            break
          end
        end
        ret
      end
    
      def full?
        turn_count == cells_count
      end
    
      def draw?
        full? && !won?
      end
    
      def over?
        won? || full?
      end
    
      def winner
        won = won?
        won ? @board[won[0]] : nil
      end
    
      def play
        until over? do
          turn
        end
        if won?
          puts "Congratulations #{winner}!"
        else
          puts "Cat's Game!"
        end
      end
    end
    
    1 chơi lượt chẵn :
  • Lượt 1 :
    class TicTacToe
      attr_reader :board
      WIN_COMBINATIONS = [
        [0,1,2],
        [3,4,5],
        [6,7,8],
        [0,3,6],
        [1,4,7],
        [2,5,8],
        [0,4,8],
        [2,4,6]
      ]
    
      def initialize(board = nil, options = {})
        @options = {rows: 3, cols: 3, chr_empty: ' ', chr_separ_v: '|', chr_separ_h: '-', players: {'Player 1': 'X', 'Player 2': 'O'}}
        @options = @options.merge(options)
        @board = board || Array.new(self.cells_count, @options[:chr_empty])
      end
    
      def cells_count
        @options[:rows]*@options[:cols]
      end
    
      def get_cell_from_row_col(row, col)
        # puts "row: #{row}, col: #{col}, cell: #{((row-1)*@options[:cols])+col-1}"
        @board[((row-1)*@options[:cols])+col-1]
      end
    
      def display_board
        @options[:rows].times.with_index(1) do |r, row_index|
          str_row = ''
          @options[:cols].times.with_index(1) do |c, col_index|
            str_row += @options[:chr_empty]+get_cell_from_row_col(row_index, col_index)+@options[:chr_empty]
            str_row += @options[:chr_separ_v] if col_index < @options[:cols]
          end
          puts str_row
          puts @options[:chr_separ_h]*((@options[:cols]*3)+@options[:cols]-1) if row_index < @options[:rows]
        end
      end
    
      def input_to_index(str_input)
        str_input.to_i-1
      end
    
      def move(index, player_token)
        @board[index] = player_token
      end
    
      def position_taken?(index)
        !@board[index].strip.empty?
      end
    
      def valid_move?(index)
        index.between?(0, cells_count-1) && !position_taken?(index)
      end
    
      def turn
        puts "Enter position (1-9):"
        index = input_to_index(gets.strip)
        if valid_move?(index)
          move(index, current_player)
          display_board
        else
          turn
        end
      end
    
      def turn_count
        counter = 0
        @board.each {|cell| counter += 1 unless cell.strip.empty?}
        counter
      end
    
      def current_player
        turn_count % 2 == 0 ? 'X' : 'O'
      end
    
      def won?
        ret = nil
        WIN_COMBINATIONS.each do |wc|
          if wc.all? { |index| position_taken?(index) && @board[index] == @board[wc[0]]}
            ret = wc
            break
          end
        end
        ret
      end
    
      def full?
        turn_count == cells_count
      end
    
      def draw?
        full? && !won?
      end
    
      def over?
        won? || full?
      end
    
      def winner
        won = won?
        won ? @board[won[0]] : nil
      end
    
      def play
        until over? do
          turn
        end
        if won?
          puts "Congratulations #{winner}!"
        else
          puts "Cat's Game!"
        end
      end
    end
    
    0 sẽ điền X vào 1 ô trong
     X | O | X   
    -----------
     O | X | O   
    -----------
     O | X | O  
    => Cat's game
    
    3
  • Lượt 2 :
    class TicTacToe
      attr_reader :board
      WIN_COMBINATIONS = [
        [0,1,2],
        [3,4,5],
        [6,7,8],
        [0,3,6],
        [1,4,7],
        [2,5,8],
        [0,4,8],
        [2,4,6]
      ]
    
      def initialize(board = nil, options = {})
        @options = {rows: 3, cols: 3, chr_empty: ' ', chr_separ_v: '|', chr_separ_h: '-', players: {'Player 1': 'X', 'Player 2': 'O'}}
        @options = @options.merge(options)
        @board = board || Array.new(self.cells_count, @options[:chr_empty])
      end
    
      def cells_count
        @options[:rows]*@options[:cols]
      end
    
      def get_cell_from_row_col(row, col)
        # puts "row: #{row}, col: #{col}, cell: #{((row-1)*@options[:cols])+col-1}"
        @board[((row-1)*@options[:cols])+col-1]
      end
    
      def display_board
        @options[:rows].times.with_index(1) do |r, row_index|
          str_row = ''
          @options[:cols].times.with_index(1) do |c, col_index|
            str_row += @options[:chr_empty]+get_cell_from_row_col(row_index, col_index)+@options[:chr_empty]
            str_row += @options[:chr_separ_v] if col_index < @options[:cols]
          end
          puts str_row
          puts @options[:chr_separ_h]*((@options[:cols]*3)+@options[:cols]-1) if row_index < @options[:rows]
        end
      end
    
      def input_to_index(str_input)
        str_input.to_i-1
      end
    
      def move(index, player_token)
        @board[index] = player_token
      end
    
      def position_taken?(index)
        !@board[index].strip.empty?
      end
    
      def valid_move?(index)
        index.between?(0, cells_count-1) && !position_taken?(index)
      end
    
      def turn
        puts "Enter position (1-9):"
        index = input_to_index(gets.strip)
        if valid_move?(index)
          move(index, current_player)
          display_board
        else
          turn
        end
      end
    
      def turn_count
        counter = 0
        @board.each {|cell| counter += 1 unless cell.strip.empty?}
        counter
      end
    
      def current_player
        turn_count % 2 == 0 ? 'X' : 'O'
      end
    
      def won?
        ret = nil
        WIN_COMBINATIONS.each do |wc|
          if wc.all? { |index| position_taken?(index) && @board[index] == @board[wc[0]]}
            ret = wc
            break
          end
        end
        ret
      end
    
      def full?
        turn_count == cells_count
      end
    
      def draw?
        full? && !won?
      end
    
      def over?
        won? || full?
      end
    
      def winner
        won = won?
        won ? @board[won[0]] : nil
      end
    
      def play
        until over? do
          turn
        end
        if won?
          puts "Congratulations #{winner}!"
        else
          puts "Cat's Game!"
        end
      end
    end
    
    1 sẽ điền O vào 1 ô còn trống trong
     X | O | X   
    -----------
     O | X | O   
    -----------
     O | X | O  
    => Cat's game
    
    3còn trống trong
     X | O | X   
    -----------
     O | X | O   
    -----------
     O | X | O  
    => Cat's game
    
    3
  • Lượt 3 :
    class TicTacToe
      attr_reader :board
      WIN_COMBINATIONS = [
        [0,1,2],
        [3,4,5],
        [6,7,8],
        [0,3,6],
        [1,4,7],
        [2,5,8],
        [0,4,8],
        [2,4,6]
      ]
    
      def initialize(board = nil, options = {})
        @options = {rows: 3, cols: 3, chr_empty: ' ', chr_separ_v: '|', chr_separ_h: '-', players: {'Player 1': 'X', 'Player 2': 'O'}}
        @options = @options.merge(options)
        @board = board || Array.new(self.cells_count, @options[:chr_empty])
      end
    
      def cells_count
        @options[:rows]*@options[:cols]
      end
    
      def get_cell_from_row_col(row, col)
        # puts "row: #{row}, col: #{col}, cell: #{((row-1)*@options[:cols])+col-1}"
        @board[((row-1)*@options[:cols])+col-1]
      end
    
      def display_board
        @options[:rows].times.with_index(1) do |r, row_index|
          str_row = ''
          @options[:cols].times.with_index(1) do |c, col_index|
            str_row += @options[:chr_empty]+get_cell_from_row_col(row_index, col_index)+@options[:chr_empty]
            str_row += @options[:chr_separ_v] if col_index < @options[:cols]
          end
          puts str_row
          puts @options[:chr_separ_h]*((@options[:cols]*3)+@options[:cols]-1) if row_index < @options[:rows]
        end
      end
    
      def input_to_index(str_input)
        str_input.to_i-1
      end
    
      def move(index, player_token)
        @board[index] = player_token
      end
    
      def position_taken?(index)
        !@board[index].strip.empty?
      end
    
      def valid_move?(index)
        index.between?(0, cells_count-1) && !position_taken?(index)
      end
    
      def turn
        puts "Enter position (1-9):"
        index = input_to_index(gets.strip)
        if valid_move?(index)
          move(index, current_player)
          display_board
        else
          turn
        end
      end
    
      def turn_count
        counter = 0
        @board.each {|cell| counter += 1 unless cell.strip.empty?}
        counter
      end
    
      def current_player
        turn_count % 2 == 0 ? 'X' : 'O'
      end
    
      def won?
        ret = nil
        WIN_COMBINATIONS.each do |wc|
          if wc.all? { |index| position_taken?(index) && @board[index] == @board[wc[0]]}
            ret = wc
            break
          end
        end
        ret
      end
    
      def full?
        turn_count == cells_count
      end
    
      def draw?
        full? && !won?
      end
    
      def over?
        won? || full?
      end
    
      def winner
        won = won?
        won ? @board[won[0]] : nil
      end
    
      def play
        until over? do
          turn
        end
        if won?
          puts "Congratulations #{winner}!"
        else
          puts "Cat's Game!"
        end
      end
    end
    
    0 sẽ điền X vào 1 ô còn trống trong
     X | O | X   
    -----------
     O | X | O   
    -----------
     O | X | O  
    => Cat's game
    
    3 .......còn trống trong
     X | O | X   
    -----------
     O | X | O   
    -----------
     O | X | O  
    => Cat's game
    
    3 .......
  • Lượt 9 :
    class TicTacToe
      attr_reader :board
      WIN_COMBINATIONS = [
        [0,1,2],
        [3,4,5],
        [6,7,8],
        [0,3,6],
        [1,4,7],
        [2,5,8],
        [0,4,8],
        [2,4,6]
      ]
    
      def initialize(board = nil, options = {})
        @options = {rows: 3, cols: 3, chr_empty: ' ', chr_separ_v: '|', chr_separ_h: '-', players: {'Player 1': 'X', 'Player 2': 'O'}}
        @options = @options.merge(options)
        @board = board || Array.new(self.cells_count, @options[:chr_empty])
      end
    
      def cells_count
        @options[:rows]*@options[:cols]
      end
    
      def get_cell_from_row_col(row, col)
        # puts "row: #{row}, col: #{col}, cell: #{((row-1)*@options[:cols])+col-1}"
        @board[((row-1)*@options[:cols])+col-1]
      end
    
      def display_board
        @options[:rows].times.with_index(1) do |r, row_index|
          str_row = ''
          @options[:cols].times.with_index(1) do |c, col_index|
            str_row += @options[:chr_empty]+get_cell_from_row_col(row_index, col_index)+@options[:chr_empty]
            str_row += @options[:chr_separ_v] if col_index < @options[:cols]
          end
          puts str_row
          puts @options[:chr_separ_h]*((@options[:cols]*3)+@options[:cols]-1) if row_index < @options[:rows]
        end
      end
    
      def input_to_index(str_input)
        str_input.to_i-1
      end
    
      def move(index, player_token)
        @board[index] = player_token
      end
    
      def position_taken?(index)
        !@board[index].strip.empty?
      end
    
      def valid_move?(index)
        index.between?(0, cells_count-1) && !position_taken?(index)
      end
    
      def turn
        puts "Enter position (1-9):"
        index = input_to_index(gets.strip)
        if valid_move?(index)
          move(index, current_player)
          display_board
        else
          turn
        end
      end
    
      def turn_count
        counter = 0
        @board.each {|cell| counter += 1 unless cell.strip.empty?}
        counter
      end
    
      def current_player
        turn_count % 2 == 0 ? 'X' : 'O'
      end
    
      def won?
        ret = nil
        WIN_COMBINATIONS.each do |wc|
          if wc.all? { |index| position_taken?(index) && @board[index] == @board[wc[0]]}
            ret = wc
            break
          end
        end
        ret
      end
    
      def full?
        turn_count == cells_count
      end
    
      def draw?
        full? && !won?
      end
    
      def over?
        won? || full?
      end
    
      def winner
        won = won?
        won ? @board[won[0]] : nil
      end
    
      def play
        until over? do
          turn
        end
        if won?
          puts "Congratulations #{winner}!"
        else
          puts "Cat's Game!"
        end
      end
    end
    
    0 sẽ điền X vào 1 ô còn trống trong
     X | O | X   
    -----------
     O | X | O   
    -----------
     O | X | O  
    => Cat's game
    
    3còn trống trong
     X | O | X   
    -----------
     O | X | O   
    -----------
     O | X | O  
    => Cat's game
    
    3

Khi 9 ô trong

 X | O | X   
-----------
 O | X | O   
-----------
 O | X | O  
=> Cat's game
3 được điền đầy
 X | O | X   
-----------
 O | X | O   
-----------
 O | X | O  
=> Cat's game
4 thì game kết thúc ở 1 trong 3 trạng thái :

  • Player 1 thắng.
 X | X | X   
-----------
 O |   |    
-----------
   | O | O   
 => Congratulations X!
  • Player 2 thắng
 X |   | X   
-----------
   | X |    
-----------
 O | O | O  
=> Congratulations O!
  • Hòa.
 X | O | X   
-----------
 O | X | O   
-----------
 O | X | O  
=> Cat's game

2. Giải thích sourecode của trang codingame.

Dưới đây là 116 dòng sourecode của class TicTacToe trên trang

  def initialize
    @options = {rows: 3, cols: 3, chr_empty: ' ', chr_separ_v: '|', chr_separ_h: '-', players: {'Player 1': 'X', 'Player 2': 'O'}}
    @board = Array.new(self.cells_count, @options[:chr_empty])
  end
  
  def cells_count
    @options[:rows]*@options[:cols]
  end
2 nói trên:

class TicTacToe
  attr_reader :board
  WIN_COMBINATIONS = [
    [0,1,2],
    [3,4,5],
    [6,7,8],
    [0,3,6],
    [1,4,7],
    [2,5,8],
    [0,4,8],
    [2,4,6]
  ]

  def initialize(board = nil, options = {})
    @options = {rows: 3, cols: 3, chr_empty: ' ', chr_separ_v: '|', chr_separ_h: '-', players: {'Player 1': 'X', 'Player 2': 'O'}}
    @options = @options.merge(options)
    @board = board || Array.new(self.cells_count, @options[:chr_empty])
  end

  def cells_count
    @options[:rows]*@options[:cols]
  end

  def get_cell_from_row_col(row, col)
    # puts "row: #{row}, col: #{col}, cell: #{((row-1)*@options[:cols])+col-1}"
    @board[((row-1)*@options[:cols])+col-1]
  end

  def display_board
    @options[:rows].times.with_index(1) do |r, row_index|
      str_row = ''
      @options[:cols].times.with_index(1) do |c, col_index|
        str_row += @options[:chr_empty]+get_cell_from_row_col(row_index, col_index)+@options[:chr_empty]
        str_row += @options[:chr_separ_v] if col_index < @options[:cols]
      end
      puts str_row
      puts @options[:chr_separ_h]*((@options[:cols]*3)+@options[:cols]-1) if row_index < @options[:rows]
    end
  end

  def input_to_index(str_input)
    str_input.to_i-1
  end

  def move(index, player_token)
    @board[index] = player_token
  end

  def position_taken?(index)
    !@board[index].strip.empty?
  end

  def valid_move?(index)
    index.between?(0, cells_count-1) && !position_taken?(index)
  end

  def turn
    puts "Enter position (1-9):"
    index = input_to_index(gets.strip)
    if valid_move?(index)
      move(index, current_player)
      display_board
    else
      turn
    end
  end

  def turn_count
    counter = 0
    @board.each {|cell| counter += 1 unless cell.strip.empty?}
    counter
  end

  def current_player
    turn_count % 2 == 0 ? 'X' : 'O'
  end

  def won?
    ret = nil
    WIN_COMBINATIONS.each do |wc|
      if wc.all? { |index| position_taken?(index) && @board[index] == @board[wc[0]]}
        ret = wc
        break
      end
    end
    ret
  end

  def full?
    turn_count == cells_count
  end

  def draw?
    full? && !won?
  end

  def over?
    won? || full?
  end

  def winner
    won = won?
    won ? @board[won[0]] : nil
  end

  def play
    until over? do
      turn
    end
    if won?
      puts "Congratulations #{winner}!"
    else
      puts "Cat's Game!"
    end
  end
end

Bây giờ, mình sẽ đi vào giải thích 17

  def initialize
    @options = {rows: 3, cols: 3, chr_empty: ' ', chr_separ_v: '|', chr_separ_h: '-', players: {'Player 1': 'X', 'Player 2': 'O'}}
    @board = Array.new(self.cells_count, @options[:chr_empty])
  end
  
  def cells_count
    @options[:rows]*@options[:cols]
  end
3 bên trên theo
  def initialize
    @options = {rows: 3, cols: 3, chr_empty: ' ', chr_separ_v: '|', chr_separ_h: '-', players: {'Player 1': 'X', 'Player 2': 'O'}}
    @board = Array.new(self.cells_count, @options[:chr_empty])
  end
  
  def cells_count
    @options[:rows]*@options[:cols]
  end
4 của game .

2.1 Tạo màn chơi mới.

Để tạo một màn chơi mới, ta cần khởi tạo một đối tượng của

 X | O | X   
-----------
 O | X | O   
-----------
 O | X | O  
=> Cat's game
1 bằng
  def initialize
    @options = {rows: 3, cols: 3, chr_empty: ' ', chr_separ_v: '|', chr_separ_h: '-', players: {'Player 1': 'X', 'Player 2': 'O'}}
    @board = Array.new(self.cells_count, @options[:chr_empty])
  end
  
  def cells_count
    @options[:rows]*@options[:cols]
  end
6 (
  def initialize
    @options = {rows: 3, cols: 3, chr_empty: ' ', chr_separ_v: '|', chr_separ_h: '-', players: {'Player 1': 'X', 'Player 2': 'O'}}
    @board = Array.new(self.cells_count, @options[:chr_empty])
  end
  
  def cells_count
    @options[:rows]*@options[:cols]
  end
7 của nó là
  def initialize
    @options = {rows: 3, cols: 3, chr_empty: ' ', chr_separ_v: '|', chr_separ_h: '-', players: {'Player 1': 'X', 'Player 2': 'O'}}
    @board = Array.new(self.cells_count, @options[:chr_empty])
  end
  
  def cells_count
    @options[:rows]*@options[:cols]
  end
8 )

  def initialize
    @options = {rows: 3, cols: 3, chr_empty: ' ', chr_separ_v: '|', chr_separ_h: '-', players: {'Player 1': 'X', 'Player 2': 'O'}}
    @board = Array.new(self.cells_count, @options[:chr_empty])
  end
  
  def cells_count
    @options[:rows]*@options[:cols]
  end
irb(main):119:0> game = TicTacToe.new
=> #3, :cols=>3, :chr_empty=>" ", :chr_separ_v=>"|", :chr_separ_h=>"-", :players=>{:"Player 1"=>"X", :"Player 2"=>"O"}}, @board=[" ", " ", " ", " ", " ", " ", " ", " ", " "]>

Ta lưu màn chơi mới này bằng biến

  def initialize
    @options = {rows: 3, cols: 3, chr_empty: ' ', chr_separ_v: '|', chr_separ_h: '-', players: {'Player 1': 'X', 'Player 2': 'O'}}
    @board = Array.new(self.cells_count, @options[:chr_empty])
  end
  
  def cells_count
    @options[:rows]*@options[:cols]
  end
9 với 2 giá trị quan trọng là được lưu vào các instance variable:
irb(main):119:0> game = TicTacToe.new
=> #3, :cols=>3, :chr_empty=>" ", :chr_separ_v=>"|", :chr_separ_h=>"-", :players=>{:"Player 1"=>"X", :"Player 2"=>"O"}}, @board=[" ", " ", " ", " ", " ", " ", " ", " ", " "]>
0 và
irb(main):119:0> game = TicTacToe.new
=> #3, :cols=>3, :chr_empty=>" ", :chr_separ_v=>"|", :chr_separ_h=>"-", :players=>{:"Player 1"=>"X", :"Player 2"=>"O"}}, @board=[" ", " ", " ", " ", " ", " ", " ", " ", " "]>
1 . Mình sẽ giải thích về 2 giá trị này.

irb(main):119:0> game = TicTacToe.new
=> #3, :cols=>3, :chr_empty=>" ", :chr_separ_v=>"|", :chr_separ_h=>"-", :players=>{:"Player 1"=>"X", :"Player 2"=>"O"}}, @board=[" ", " ", " ", " ", " ", " ", " ", " ", " "]>
0 là một
irb(main):119:0> game = TicTacToe.new
=> #3, :cols=>3, :chr_empty=>" ", :chr_separ_v=>"|", :chr_separ_h=>"-", :players=>{:"Player 1"=>"X", :"Player 2"=>"O"}}, @board=[" ", " ", " ", " ", " ", " ", " ", " ", " "]>
3 lưu các giá trị liên quan đến settings của trò chơi.

  • irb(main):119:0> game = TicTacToe.new
    => #3, :cols=>3, :chr_empty=>" ", :chr_separ_v=>"|", :chr_separ_h=>"-", :players=>{:"Player 1"=>"X", :"Player 2"=>"O"}}, @board=[" ", " ", " ", " ", " ", " ", " ", " ", " "]>
    
    4 và
    irb(main):119:0> game = TicTacToe.new
    => #3, :cols=>3, :chr_empty=>" ", :chr_separ_v=>"|", :chr_separ_h=>"-", :players=>{:"Player 1"=>"X", :"Player 2"=>"O"}}, @board=[" ", " ", " ", " ", " ", " ", " ", " ", " "]>
    
    5 lưu số hàng và số cột của
     X | O | X   
    -----------
     O | X | O   
    -----------
     O | X | O  
    => Cat's game
    
    3 . (ở đây mặc định là 3x3) .
  • irb(main):119:0> game = TicTacToe.new
    => #3, :cols=>3, :chr_empty=>" ", :chr_separ_v=>"|", :chr_separ_h=>"-", :players=>{:"Player 1"=>"X", :"Player 2"=>"O"}}, @board=[" ", " ", " ", " ", " ", " ", " ", " ", " "]>
    
    7,
    irb(main):119:0> game = TicTacToe.new
    => #3, :cols=>3, :chr_empty=>" ", :chr_separ_v=>"|", :chr_separ_h=>"-", :players=>{:"Player 1"=>"X", :"Player 2"=>"O"}}, @board=[" ", " ", " ", " ", " ", " ", " ", " ", " "]>
    
    8,
    irb(main):119:0> game = TicTacToe.new
    => #3, :cols=>3, :chr_empty=>" ", :chr_separ_v=>"|", :chr_separ_h=>"-", :players=>{:"Player 1"=>"X", :"Player 2"=>"O"}}, @board=[" ", " ", " ", " ", " ", " ", " ", " ", " "]>
    
    9 lưu các ký tự để vẽ lên board trong terminal như sau:
   |   |   
-----------
   |   |   
-----------
   |   |   
  •    |   |   
    -----------
       |   |   
    -----------
       |   |   
    
    0 =
       |   |   
    -----------
       |   |   
    -----------
       |   |   
    
    1 là 1 hash lưu lại token của Player 1 và Player 2, phục vụ cho mục đích truy xuất xem cuối cùng ai là người thắng cuộc.

Về giá trị

irb(main):119:0> game = TicTacToe.new
=> #3, :cols=>3, :chr_empty=>" ", :chr_separ_v=>"|", :chr_separ_h=>"-", :players=>{:"Player 1"=>"X", :"Player 2"=>"O"}}, @board=[" ", " ", " ", " ", " ", " ", " ", " ", " "]>
1, nó là một mảng lưu lại tất cả giá trị 'X', 'O' đã được điền trong suốt màn chơi. Cụ thể, các giá trị của
irb(main):119:0> game = TicTacToe.new
=> #3, :cols=>3, :chr_empty=>" ", :chr_separ_v=>"|", :chr_separ_h=>"-", :players=>{:"Player 1"=>"X", :"Player 2"=>"O"}}, @board=[" ", " ", " ", " ", " ", " ", " ", " ", " "]>
1 thể hiện trên màn hình như sau:

 @board[0] | @board[1] | @board[2]  
----------------------------------
 @board[3] | @board[4] | @board[5]  
----------------------------------
 @board[6] | @board[7] | @board[8]  

Như vậy, quá trình chơi game tương ứng với quá trị gán giá trị cho các phần từ từ

   |   |   
-----------
   |   |   
-----------
   |   |   
4 . Khi khởi tạo một đối tượng, mặc định 1 board sẽ được tạo ra

2.2 Hiển thị board

Như vậy là ta đã tạo xong một màn chơi mới, giờ ta sẽ thử hiển thị board của màn chơi mới bằng

   |   |   
-----------
   |   |   
-----------
   |   |   
5 :

  def get_cell_from_row_col(row, col)
    @board[((row-1)*@options[:cols])+col-1]
  end

  def display_board
    @options[:rows].times.with_index(1) do |r, row_index|
      str_row = ''
      @options[:cols].times.with_index(1) do |c, col_index|
        str_row += @options[:chr_empty]+get_cell_from_row_col(row_index, col_index)+@options[:chr_empty]
        str_row += @options[:chr_separ_v] if col_index < @options[:cols]
      end
      puts str_row
      puts @options[:chr_separ_h]*((@options[:cols]*3)+@options[:cols]-1) if row_index < @options[:rows]
    end
  end

Hình ảnh board của màn chơi mới khởi tạo:

 X | X | X   
-----------
 O |   |    
-----------
   | O | O   
 => Congratulations X!
0

Mình sẽ giải thích về

   |   |   
-----------
   |   |   
-----------
   |   |   
5 . Trước hết, ta thấy việc hiển thị
 X | O | X   
-----------
 O | X | O   
-----------
 O | X | O  
=> Cat's game
3 trên màn hình giống như việc in ra ma trận từ một mảng 2 chiều. Tuy nhiên ở đây, mình lưu
 X | O | X   
-----------
 O | X | O   
-----------
 O | X | O  
=> Cat's game
3 dưới dạng mảng 1 chiều
irb(main):119:0> game = TicTacToe.new
=> #3, :cols=>3, :chr_empty=>" ", :chr_separ_v=>"|", :chr_separ_h=>"-", :players=>{:"Player 1"=>"X", :"Player 2"=>"O"}}, @board=[" ", " ", " ", " ", " ", " ", " ", " ", " "]>
1, nên mình cần có thêm 1 method sau:

 X | X | X   
-----------
 O |   |    
-----------
   | O | O   
 => Congratulations X!
1

 @board[0] | @board[1] | @board[2]  
----------------------------------
 @board[3] | @board[4] | @board[5]  
----------------------------------
 @board[6] | @board[7] | @board[8]  
0 sẽ trả về giá trị 'X' hoặc 'O' tương ứng trong
 X | O | X   
-----------
 O | X | O   
-----------
 O | X | O  
=> Cat's game
3 , khi biết chỉ số hàng và cột. Cụ thể:

 X | X | X   
-----------
 O |   |    
-----------
   | O | O   
 => Congratulations X!
2
 @board[0] | @board[1] | @board[2]  
----------------------------------
 @board[3] | @board[4] | @board[5]  
----------------------------------
 @board[6] | @board[7] | @board[8]  

Ví dụ,

  • với row = 1, col = 1 ,
     @board[0] | @board[1] | @board[2]  
    ----------------------------------
     @board[3] | @board[4] | @board[5]  
    ----------------------------------
     @board[6] | @board[7] | @board[8]  
    
    0 trả về giá trị
     @board[0] | @board[1] | @board[2]  
    ----------------------------------
     @board[3] | @board[4] | @board[5]  
    ----------------------------------
     @board[6] | @board[7] | @board[8]  
    
    3
  • với row = 2, col = 3 ,
     @board[0] | @board[1] | @board[2]  
    ----------------------------------
     @board[3] | @board[4] | @board[5]  
    ----------------------------------
     @board[6] | @board[7] | @board[8]  
    
    0 trả về giá trị
     @board[0] | @board[1] | @board[2]  
    ----------------------------------
     @board[3] | @board[4] | @board[5]  
    ----------------------------------
     @board[6] | @board[7] | @board[8]  
    
    5

Trở lại với

   |   |   
-----------
   |   |   
-----------
   |   |   
5, mình sẽ giải thích nó bằng comment trong code:

 X | X | X   
-----------
 O |   |    
-----------
   | O | O   
 => Congratulations X!
4

2.3 Chơi game thôi .

Sau khi khởi tạo màn chơi, chúng ta sẽ bắt đầu chơi bằng

 X | O | X   
-----------
 O | X | O   
-----------
 O | X | O  
=> Cat's game
0
 @board[0] | @board[1] | @board[2]  
----------------------------------
 @board[3] | @board[4] | @board[5]  
----------------------------------
 @board[6] | @board[7] | @board[8]  
8 : Về method play: Về method play:

 X | X | X   
-----------
 O |   |    
-----------
   | O | O   
 => Congratulations X!
5

Để hiểu

 X | O | X   
-----------
 O | X | O   
-----------
 O | X | O  
=> Cat's game
0
 @board[0] | @board[1] | @board[2]  
----------------------------------
 @board[3] | @board[4] | @board[5]  
----------------------------------
 @board[6] | @board[7] | @board[8]  
8, chúng ta phải hiểu được các
 X | O | X   
-----------
 O | X | O   
-----------
 O | X | O  
=> Cat's game
0
  def get_cell_from_row_col(row, col)
    @board[((row-1)*@options[:cols])+col-1]
  end

  def display_board
    @options[:rows].times.with_index(1) do |r, row_index|
      str_row = ''
      @options[:cols].times.with_index(1) do |c, col_index|
        str_row += @options[:chr_empty]+get_cell_from_row_col(row_index, col_index)+@options[:chr_empty]
        str_row += @options[:chr_separ_v] if col_index < @options[:cols]
      end
      puts str_row
      puts @options[:chr_separ_h]*((@options[:cols]*3)+@options[:cols]-1) if row_index < @options[:rows]
    end
  end
2 ,
  def get_cell_from_row_col(row, col)
    @board[((row-1)*@options[:cols])+col-1]
  end

  def display_board
    @options[:rows].times.with_index(1) do |r, row_index|
      str_row = ''
      @options[:cols].times.with_index(1) do |c, col_index|
        str_row += @options[:chr_empty]+get_cell_from_row_col(row_index, col_index)+@options[:chr_empty]
        str_row += @options[:chr_separ_v] if col_index < @options[:cols]
      end
      puts str_row
      puts @options[:chr_separ_h]*((@options[:cols]*3)+@options[:cols]-1) if row_index < @options[:rows]
    end
  end
3,
  def get_cell_from_row_col(row, col)
    @board[((row-1)*@options[:cols])+col-1]
  end

  def display_board
    @options[:rows].times.with_index(1) do |r, row_index|
      str_row = ''
      @options[:cols].times.with_index(1) do |c, col_index|
        str_row += @options[:chr_empty]+get_cell_from_row_col(row_index, col_index)+@options[:chr_empty]
        str_row += @options[:chr_separ_v] if col_index < @options[:cols]
      end
      puts str_row
      puts @options[:chr_separ_h]*((@options[:cols]*3)+@options[:cols]-1) if row_index < @options[:rows]
    end
  end
4,
  def get_cell_from_row_col(row, col)
    @board[((row-1)*@options[:cols])+col-1]
  end

  def display_board
    @options[:rows].times.with_index(1) do |r, row_index|
      str_row = ''
      @options[:cols].times.with_index(1) do |c, col_index|
        str_row += @options[:chr_empty]+get_cell_from_row_col(row_index, col_index)+@options[:chr_empty]
        str_row += @options[:chr_separ_v] if col_index < @options[:cols]
      end
      puts str_row
      puts @options[:chr_separ_h]*((@options[:cols]*3)+@options[:cols]-1) if row_index < @options[:rows]
    end
  end
5.

2.3.1 Method over?

Với

  def get_cell_from_row_col(row, col)
    @board[((row-1)*@options[:cols])+col-1]
  end

  def display_board
    @options[:rows].times.with_index(1) do |r, row_index|
      str_row = ''
      @options[:cols].times.with_index(1) do |c, col_index|
        str_row += @options[:chr_empty]+get_cell_from_row_col(row_index, col_index)+@options[:chr_empty]
        str_row += @options[:chr_separ_v] if col_index < @options[:cols]
      end
      puts str_row
      puts @options[:chr_separ_h]*((@options[:cols]*3)+@options[:cols]-1) if row_index < @options[:rows]
    end
  end
6 :

 X | X | X   
-----------
 O |   |    
-----------
   | O | O   
 => Congratulations X!
6

  def get_cell_from_row_col(row, col)
    @board[((row-1)*@options[:cols])+col-1]
  end

  def display_board
    @options[:rows].times.with_index(1) do |r, row_index|
      str_row = ''
      @options[:cols].times.with_index(1) do |c, col_index|
        str_row += @options[:chr_empty]+get_cell_from_row_col(row_index, col_index)+@options[:chr_empty]
        str_row += @options[:chr_separ_v] if col_index < @options[:cols]
      end
      puts str_row
      puts @options[:chr_separ_h]*((@options[:cols]*3)+@options[:cols]-1) if row_index < @options[:rows]
    end
  end
7 dùng để kiểm tra xem màn chơi đã kết thúc chưa. Màn chơi kết thúc chỉ trong 2 trường hợp:

  • TH1: Có 1 người chơi thắng trước khi
     X | O | X   
    -----------
     O | X | O   
    -----------
     O | X | O  
    => Cat's game
    
    3 bị đầy.

Trường hợp này sẽ được kiểm tra bằng

  def get_cell_from_row_col(row, col)
    @board[((row-1)*@options[:cols])+col-1]
  end

  def display_board
    @options[:rows].times.with_index(1) do |r, row_index|
      str_row = ''
      @options[:cols].times.with_index(1) do |c, col_index|
        str_row += @options[:chr_empty]+get_cell_from_row_col(row_index, col_index)+@options[:chr_empty]
        str_row += @options[:chr_separ_v] if col_index < @options[:cols]
      end
      puts str_row
      puts @options[:chr_separ_h]*((@options[:cols]*3)+@options[:cols]-1) if row_index < @options[:rows]
    end
  end
9 dưới đây, và mình sẽ giải thích về cách mà nó hoạt động.

 X | X | X   
-----------
 O |   |    
-----------
   | O | O   
 => Congratulations X!
7

Người chơi

 X | O | X   
-----------
 O | X | O   
-----------
 O | X | O  
=> Cat's game
6 được xác nhận là dành chiến thắng khi và chỉ khi có 3
 X | O | X   
-----------
 O | X | O   
-----------
 O | X | O  
=> Cat's game
4
 X | O | X   
-----------
 O | X | O   
-----------
 O | X | O  
=> Cat's game
6 được điền vào
 X | O | X   
-----------
 O | X | O   
-----------
 O | X | O  
=> Cat's game
3 ở tổ hợp các vị trí sau:

 X | X | X   
-----------
 O |   |    
-----------
   | O | O   
 => Congratulations X!
8

Điều tương tự xảy ra với người chơi

 X | O | X   
-----------
 O | X | O   
-----------
 O | X | O  
=> Cat's game
7 .

Xét các tổ hợp vị trí nói trên, ta suy ra được 8 trường hợp tương ứng với việc một trong 2 người chơi dành chiến thắng:8 trường hợp tương ứng với việc một trong 2 người chơi dành chiến thắng:

 X | X | X   
-----------
 O |   |    
-----------
   | O | O   
 => Congratulations X!
9

8 trường hợp dành chiến thắng này được lưu bởi hằng số

 X | X | X   
-----------
 O |   |    
-----------
   | O | O   
 => Congratulations X!
05 . Sau khi hiểu được hằng số này, việc hiểu
  def get_cell_from_row_col(row, col)
    @board[((row-1)*@options[:cols])+col-1]
  end

  def display_board
    @options[:rows].times.with_index(1) do |r, row_index|
      str_row = ''
      @options[:cols].times.with_index(1) do |c, col_index|
        str_row += @options[:chr_empty]+get_cell_from_row_col(row_index, col_index)+@options[:chr_empty]
        str_row += @options[:chr_separ_v] if col_index < @options[:cols]
      end
      puts str_row
      puts @options[:chr_separ_h]*((@options[:cols]*3)+@options[:cols]-1) if row_index < @options[:rows]
    end
  end
9 trở lên dễ dàng hơn:
dành chiến thắng này được lưu bởi hằng số
 X | X | X   
-----------
 O |   |    
-----------
   | O | O   
 => Congratulations X!
05 . Sau khi hiểu được hằng số này, việc hiểu
  def get_cell_from_row_col(row, col)
    @board[((row-1)*@options[:cols])+col-1]
  end

  def display_board
    @options[:rows].times.with_index(1) do |r, row_index|
      str_row = ''
      @options[:cols].times.with_index(1) do |c, col_index|
        str_row += @options[:chr_empty]+get_cell_from_row_col(row_index, col_index)+@options[:chr_empty]
        str_row += @options[:chr_separ_v] if col_index < @options[:cols]
      end
      puts str_row
      puts @options[:chr_separ_h]*((@options[:cols]*3)+@options[:cols]-1) if row_index < @options[:rows]
    end
  end
9 trở lên dễ dàng hơn:

 X |   | X   
-----------
   | X |    
-----------
 O | O | O  
=> Congratulations O!
0
  • TH2: Board bị đầy . Tức là
    irb(main):119:0> game = TicTacToe.new
    => #3, :cols=>3, :chr_empty=>" ", :chr_separ_v=>"|", :chr_separ_h=>"-", :players=>{:"Player 1"=>"X", :"Player 2"=>"O"}}, @board=[" ", " ", " ", " ", " ", " ", " ", " ", " "]>
    
    1 đã đủ 9 phần tử có giá trị 'X' hoặc 'O' .

Trường hợp này được kiểm tra bằng

 X | X | X   
-----------
 O |   |    
-----------
   | O | O   
 => Congratulations X!
08 khá dễ hiểu:

 X |   | X   
-----------
   | X |    
-----------
 O | O | O  
=> Congratulations O!
1

2.3.2 Method turn

 X | X | X   
-----------
 O |   |    
-----------
   | O | O   
 => Congratulations X!
09 được dùng để nhập token ở mỗi lượt chơi của 2 player như sau:

 X |   | X   
-----------
   | X |    
-----------
 O | O | O  
=> Congratulations O!
2

Như vậy là mình đã giải thích xong cách mà các method trong

 X |   | X   
-----------
   | X |    
-----------
 O | O | O  
=> Congratulations O!
9 hoạt động. Giờ chúng ta cùng thử tìm cách sửa lại
 X |   | X   
-----------
   | X |    
-----------
 O | O | O  
=> Congratulations O!
9 này 1 chút để tạo ra các game cờ caro 4x4 hoặc 5x5 .

3. Thử tạo ra game cờ caro nxn (n>3)

Để tạo ra game cờ caro nxn (n>3) khá đơn giản, chúng ta chỉ cần sửa lại

irb(main):119:0> game = TicTacToe.new
=> #3, :cols=>3, :chr_empty=>" ", :chr_separ_v=>"|", :chr_separ_h=>"-", :players=>{:"Player 1"=>"X", :"Player 2"=>"O"}}, @board=[" ", " ", " ", " ", " ", " ", " ", " ", " "]>
0 và hằng số
 X | X | X   
-----------
 O |   |    
-----------
   | O | O   
 => Congratulations X!
05 một chút.

Mình sẽ thử với trường hợp 4x4 . Đầu tiên, với biến

irb(main):119:0> game = TicTacToe.new
=> #3, :cols=>3, :chr_empty=>" ", :chr_separ_v=>"|", :chr_separ_h=>"-", :players=>{:"Player 1"=>"X", :"Player 2"=>"O"}}, @board=[" ", " ", " ", " ", " ", " ", " ", " ", " "]>
0 trong
 X | X | X   
-----------
 O |   |    
-----------
   | O | O   
 => Congratulations X!
15, chúng ta sẽ sửa số
 X | X | X   
-----------
 O |   |    
-----------
   | O | O   
 => Congratulations X!
16 và
 X | X | X   
-----------
 O |   |    
-----------
   | O | O   
 => Congratulations X!
17 thành 4.

 X |   | X   
-----------
   | X |    
-----------
 O | O | O  
=> Congratulations O!
3

Tiếp theo, chúng ta sửa

 X | X | X   
-----------
 O |   |    
-----------
   | O | O   
 => Congratulations X!
05 như sau:

 X |   | X   
-----------
   | X |    
-----------
 O | O | O  
=> Congratulations O!
4

Toàn bộ phần

 X |   | X   
-----------
   | X |    
-----------
 O | O | O  
=> Congratulations O!
9 còn lại của game 3x3 sẽ được giữ nguyên và ta có
 X |   | X   
-----------
   | X |    
-----------
 O | O | O  
=> Congratulations O!
9 mới cho game cờ caro 4x4 như sau:

 X |   | X   
-----------
   | X |    
-----------
 O | O | O  
=> Congratulations O!
5

Mình sẽ thử chơi với

 X |   | X   
-----------
   | X |    
-----------
 O | O | O  
=> Congratulations O!
9 mới nhé:

Như vậy mấu chốt để tạo ra game cờ caro

 X | X | X   
-----------
 O |   |    
-----------
   | O | O   
 => Congratulations X!
22 là hằng số
 X | X | X   
-----------
 O |   |    
-----------
   | O | O   
 => Congratulations X!
05 . Chúng ta có thể nhận thấy 1 quy luật khá rõ ràng:

 X |   | X   
-----------
   | X |    
-----------
 O | O | O  
=> Congratulations O!
6

Với n < 8, các bạn hoàn toàn có thể dùng

 X | X | X   
-----------
 O |   |    
-----------
   | O | O   
 => Congratulations X!
24 để thiết lập
 X | X | X   
-----------
 O |   |    
-----------
   | O | O   
 => Congratulations X!
05 . Tuy nhiên với n = 20 chẳng hạn, ngồi tìm ra 42 phần tử của
 X | X | X   
-----------
 O |   |    
-----------
   | O | O   
 => Congratulations X!
05 đúng là mắc mợt . Cách tốt nhất là chúng ta nên viết một method để sinh ra
 X | X | X   
-----------
 O |   |    
-----------
   | O | O   
 => Congratulations X!
05 với tham số là n. Tuy nhiên, bài viết đến đây là đủ dài rồi, mình sẽ chia sẻ thuật toán để viết method này vào part 2 của bài viết.

4. Tạm biệt

Chốt lại, ở các phần sau của bài viết, mình sẽ giải quyết các vấn đề sau:

  • Thuật toán tạo
     X | X | X   
    -----------
     O |   |    
    -----------
       | O | O   
     => Congratulations X!
    
    05 với tham số n cho trước.
  • Mông má thêm 1 chút HTML, CSS, JS + Rails để tạo một webgame TicTacToe

Còn bây giờ thì tạm biệt.


References:

https://www.codingame.com/playgrounds/46635/tic-tac-toe-game-implementation