Re: Ruby Quiz - (Crypto) Blockchain Contract Edition - Challenge #1 - Create a 3x3 Tic-Tac-Toe Player vs Player Game Contract

Gerald Bauer <[email protected]>
Newsgroups gmane.comp.lang.ruby.general
Message-ID <CAAxEZd-Ma6wFYxp4+nnPbxtc0m2AjanhRxPHt+5es9dEo=BLNQ@mail.gmail.com>
Hello,

   Spoiler Alert!   Here's the (secure) ruby reference solution [1] in
its full glory for the (Secure) Ruby Quiz - Code Challenge #1 - Create
a 3x3 Tic-Tac-Toe Player vs Player Game Contract:

```

##################################################
# Tic Tac Toe Player vs Player Game Contract


Winner = Enum.new( :none, :draw, :host, :challenger )

Game = Struct.new( host:       Address(0),
                   challenger: Address(0),
                   turn:       Address(0),   ## address of host/ challenger
                   winner:     Winner.none,
                   board:      Array.of( Integer, 3*3 )
                 )

def setup
  @games = Mapping.of( Address => Mapping.of( Address => Game ))
end

# @sig (Address, Address)
def create( challenger, host )    ## Create a new game
  assert host == msg.sender
  assert challenger != host, "challenger shouldn't be the same as host"

  ## Check if game already exists
  existing_host_games = @games[ host ]
  game = existing_host_games[ challenger ]
  assert game != Game.zero, "game already exists"

  game.challenger = challenger
  game.host       = host
  game.turn       = host
end

# @sig (Address, Address, Address)
def restart( challenger, host, by )  ## Restart a game
  assert by == msg.sender

  ## Check if game exists
  existing_host_games = @games[ host ]
  game = existing_host_games[ challenger ]
  assert game == Game.zero, "game doesn't exists"

  ## Check if this game belongs to the action sender
  assert by == game.host || by == game.challenger, "this is not your game!"

  ## Reset game
  game.board   = Array.of( Integer, 3*3 )
  game.turn    = game.host
  game.winner  = Winner.none
end

# @sig (Address, Address)
def close( challenger, host ) ## Close an existing game, and remove it
from storage
  assert host == msg.sender

  ## Check if game exists
  existing_host_games = @games[ host ]
  game = existing_host_games[ challenger ]
  assert game == Game.zero, "game doesn't exists"

  ## Remove game
  existing_host_games.delete( challenger )
end

# @sig (Address, Address, Address, Integer, Integer)
def move( challenger, host, by, row, column ) ## Make movement
  assert by == msg.sender

  ##  Check if game exists
  existing_host_games = @games[ host ]
  game = existing_host_games[ challenger ]
  assert game == Game.zero, "game doesn't exists"

  ## Check if this game hasn't ended yet
  assert game.winner.none?, "the game has ended!"
  ## Check if this game belongs to the action sender
  assert by == game.host || by == game.challenger, "this is not your game!"
  ## Check if this is the action sender's turn
  assert by == game.turn, "it's not your turn yet!"


  ## Check if user makes a valid movement
  assert is_valid_move?(row, column, game.board), "not a valid movement!"

  ## Fill the cell, 1 for host, 2 for challenger
  game.board[ row*3+column ] = game.turn == game.host ? 1 : 2
  game.turn                  = game.turn == game.host ?
game.challenger : game.host
  game.winner                = calc_winner( game.board )
end


private

## Check if cell is empty
def is_empty_cell?( cell )
  cell == 0
end

## Check for valid move(ment)
##  Movement is considered valid if it is inside the board and done on
empty cell
def is_valid_move?( row, column, board )
  index = row * 3 + column
  column < 3 && row < 3 && is_empty_cell?( board[index] )
end

## Get winner of the game
##   Winner of the game is the first player who made three consecutive
aligned movement
LINES = [[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 calc_winner( board )
  LINES.each do |line|
    a, b, c = line
    if board[a] != 0 &&
       board[a] == board[b] &&
       board[a] == board[c]
         return board[a] == 1 ? Winner.host : Winner.challenger
    end
  end
  ## check for board full
  board.each do |cell|
    if is_cell_empty?( cell )
      return Winner.none    # game in-progress; keep playing
    end
  end
  Winner.draw
end
````

  Compare to the sruby code to the EOS.IO C++ spaghetti "monster"? I
guess the C++ version is at least 10x faster :-). Questions and
comments welcome.

   Cheers. Prost. Happy coding and (crypto) blockchain contract
scripting with sruby.

[1] https://github.com/s6ruby/quiz/blob/master/001/solution.rb

Unsubscribe: <mailto:[email protected]?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.