El código que sigue implanta un jugador de tres-en-raya.
[~/sinatra/sinatra-tictactoe/sinatra-tictactoe-ajax(master)]$ tree . |--- Gemfile |--- Gemfile.lock |--- Procfile |--- Rakefile |--- Readme.md |--- app.rb |--- public | |--- css | | |--- app.css | | `--- style.css | |--- images | | |--- blackboard.jpg | | |--- circle.gif | | `--- cross.gif | `--- js | `--- app.js `--- views |--- final.erb |--- final.haml |--- game.erb |--- game.haml |--- layout.erb |--- layout.haml `--- styles.scss 5 directories, 19 files
[~/sinatra/sinatra-tictactoe/sinatra-tictactoe-ajax(master)]$ cat Rakefile desc "run server" task :default do sh "bundle exec ruby app.rb" end desc "install dependencies" task :install do sh "bundle install" end ### desc 'build css' task :css do sh "sass views/styles.scss public/css/style.css" end
[~/sinatra/sinatra-tictactoe/sinatra-tictactoe-ajax(master)]$ cat views/game.haml .screen .gameboard - HORIZONTALS.each do |row| .gamerow - row.each do |p| %a(href=p) %div{:id => "#{p}", :class => "cell #{b[p]}"} .message %h1= m
[~/sinatra/sinatra-tictactoe/sinatra-tictactoe-ajax(master)]$ cat views/layout.haml !!! %html %head %title tic tac toe -#%link{:rel=>"stylesheet", :href=>"/css/app.css", :type=>"text/css"} -# dynamically accessed -#%link{:rel=>"stylesheet", :href=>"/styles.css", :type=>"text/css"} -# statically compiled %link{:rel=>"stylesheet", :href=>"css/style.css", :type=>"text/css"} %script{:type=>"text/javascript", :src=>"http://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"} %script{:type=>"text/javascript", :src=>"/js/app.js"} %body = yield
styles.scss
puede compilarse dinámicamente. Véase el fragmento de código
que empieza por
get '/styles.css' do
en app.rb
<!DOCTYPE html> <html> <head> <title>tic tac toe</title> <link href='css/style.css' rel='stylesheet' type='text/css'> <script src='http://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js' type='text/javascript'></script> <script src='/js/app.js' type='text/javascript'></script> </head> <body> <div class='screen'> <div class='gameboard'> <div class='gamerow'> <a href='a1'> <div class='cell ' id='a1'></div> </a> <a href='a2'> <div class='cell ' id='a2'></div> </a> <a href='a3'> <div class='cell ' id='a3'></div> </a> </div> <div class='gamerow'> <a href='b1'> <div class='cell ' id='b1'></div> </a> <a href='b2'> <div class='cell circle' id='b2'></div> </a> <a href='b3'> <div class='cell ' id='b3'></div> </a> </div> <div class='gamerow'> <a href='c1'> <div class='cell ' id='c1'></div> </a> <a href='c2'> <div class='cell ' id='c2'></div> </a> <a href='c3'> <div class='cell cross' id='c3'></div> </a> </div> <div class='message'> <h1></h1> </div> </div> </div> </body> </html>
~/sinatra/sinatra-tictactoe/sinatra-tictactoe-ajax(master)]$ cat views/styles.scss $red: #903; $black: #444; $white: #fff; $ull: #9900FF; $pink: #F9A7B0; $main-font: Helvetica, Arial, sans-serif; $message-font: 22px/1; $board-left: 300px; $board-margin: 0 auto; $board-size: 500px; $opacity: 0.8; $cell-width: $board-size/8.5; $cell-height: $board-size/8.5; $cell-margin: $cell-width/12; $cell-padding: $cell-width/1.3; $background: "/images/blackboard.jpg"; $cross: "/images/cross.gif"; $circle: "/images/circle.gif"; body { // background-color: lightgrey; font-family: $main-font; background: url($background) repeat; background-size: cover; } .gameboard { //margin-left: $board-left; width: $board-size; margin: $board-margin; text-align:center; } .gamerow { clear: both; } .cell { color: blue; background-color: white; opacity: $opacity; width: $cell-width; height: $cell-height; margin: $cell-margin; padding: $cell-padding; &:hover { color: black ; background-color: $ull; } float: left; } @mixin game-piece($image) { background: url($image) no-repeat; background-size: cover; } .cross { @include game-piece($cross); } .circle { @include game-piece($circle); } .base-font { color: $pink; font: $message-font $main-font; } .message { @extend .base-font; display: inline; background-color:transparent; }
In order to declare the processes that make our app, and scale them individually, we need to be able to tell Heroku what these processes are.
The Procfile is a simple YAML file which sits in the root of your application code and is pushed to your application when you deploy. This file contains a definition of every process you require in your application, and how that process should be started.
[~/sinatra/sinatra-tictactoe/sinatra-tictactoe-ajax(master)]$ cat Procfile #web: bundle exec unicorn -p $PORT -E $RACK_ENV #web: bundle exec ruby app.rb -p $PORT web: bundle exec ruby app.rb #web: bundle exec thin startVéase The Procfile is your friend
[~/sinatra/sinatra-tictactoe/sinatra-tictactoe-ajax(master)]$ cat Gemfile source "https://rubygems.org" gem "sinatra" gem 'haml' gem "sass", :require => 'sass' gem 'thin'
[~/sinatra/sinatra-tictactoe/sinatra-tictactoe-ajax(master)]$ cat app.rb require 'sinatra' require 'sass' require 'pp' settings.port = ENV['PORT'] || 4567 enable :sessions #use Rack::Session::Pool, :expire_after => 2592000 #set :session_secret, 'super secret' #configure :development, :test do # set :sessions, :domain => 'example.com' #end #configure :production do # set :sessions, :domain => 'herokuapp.com' #end module TicTacToe HUMAN = CIRCLE = "circle" # human COMPUTER = CROSS = "cross" # computer BLANK = "" HORIZONTALS = [ %w{a1 a2 a3}, %w{b1 b2 b3}, %w{c1 c2 c3} ] COLUMNS = [ %w{a1 b1 c1}, %w{a2 b2 c2}, %w{a3 b3 c3} ] DIAGONALS = [ %w{a1 b2 c3}, %w{a3 b2 c1} ] ROWS = HORIZONTALS + COLUMNS + DIAGONALS MOVES = %w{a1 a2 a3 b1 b2 b3 c1 c2 c3} def number_of(symbol, row) row.find_all{ |s| session["bs"][s] == symbol }.size end def inicializa @board = {} MOVES.each do |k| @board[k] = BLANK end @board end def board session["bs"] end def [] key board[key] end def []= key, value board[key] = value end def each MOVES.each do |move| yield move end end def legal_moves m = [] MOVES.each do |key| m << key if board[key] == BLANK end puts "legal_moves: Tablero: #{board.inspect}" puts "legal_moves: m: #{m}" m # returns the set of feasible moves [ "b3", "c2", ... ] end def winner ROWS.each do |row| circles = number_of(CIRCLE, row) puts "winner: circles=#{circles}" return CIRCLE if circles == 3 # "circle" wins crosses = number_of(CROSS, row) puts "winner: crosses=#{crosses}" return CROSS if crosses == 3 end false end def smart_move moves = legal_moves ROWS.each do |row| if (number_of(BLANK, row) == 1) then if (number_of(CROSS, row) == 2) then # If I have a win, take it. row.each do |e| return e if board[e] == BLANK end end end end ROWS.each do |row| if (number_of(BLANK, row) == 1) then if (number_of(CIRCLE,row) == 2) then # If he is threatening to win, stop it. row.each do |e| return e if board[e] == BLANK end end end end # Take the center if open. return "b2" if moves.include? "b2" # Defend opposite corners. if self["a1"] != COMPUTER and self["a1"] != BLANK and self["c3"] == BLANK return "c3" elsif self["c3"] != COMPUTER and self["c3"] != BLANK and self["a1"] == BLANK return "a1" elsif self["a3"] != COMPUTER and self["a3"] != BLANK and self["c1"] == BLANK return "c1" elsif self["c1"] != COMPUTER and self["c3"] != BLANK and self["a3"] == BLANK return "a3" end # Or make a random move. moves[rand(moves.size)] end def human_wins? winner == HUMAN end def computer_wins? winner == COMPUTER end end helpers TicTacToe get %r{^/([abc][123])?$} do |human| if human then puts "You played: #{human}!" puts "session: " pp session if legal_moves.include? human board[human] = TicTacToe::CIRCLE # computer = board.legal_moves.sample computer = smart_move redirect to ('/humanwins') if human_wins? redirect to('/') unless computer board[computer] = TicTacToe::CROSS puts "I played: #{computer}!" puts "Tablero: #{board.inspect}" redirect to ('/computerwins') if computer_wins? end else session["bs"] = inicializa() puts "session = " pp session end haml :game, :locals => { :b => board, :m => '' } end get '/humanwins' do puts "/humanwins session=" pp session begin m = if human_wins? then 'Human wins' else redirect '/' end haml :final, :locals => { :b => board, :m => m } rescue redirect '/' end end get '/computerwins' do puts "/computerwins" pp session begin m = if computer_wins? then 'Computer wins' else redirect '/' end haml :final, :locals => { :b => board, :m => m } rescue redirect '/' end end not_found do puts "not found!!!!!!!!!!!" session["bs"] = inicializa() haml :game, :locals => { :b => board, :m => 'Let us start a new game' } end get '/styles.css' do scss :styles end