karel
Version:
Compilador y evaluador de Karel en javascript
483 lines (434 loc) • 14.9 kB
JavaScript
/* Cosas para dibujar el canvas del mundo */
var Kind = {
Beeper: 0,
Corner: 1,
WestWall: 2,
NorthWall: 3,
EastWall: 4,
SouthWall: 5,
Outbounds: 6,
};
var WorldRender = function (context, worldHeight, worldWidth) {
this.should_draw = true;
this.context = context;
this.primera_fila = 1;
this.primera_columna = 1;
this.num_filas = 1;
this.num_columnas = 1;
this.tamano_celda = 30;
this.margin = 7.5;
this.maxRows = worldHeight;
this.maxColumns = worldWidth;
this.polygon = false;
this.polygon_begin = undefined;
this.polygon_end = undefined;
this.paint = function (world, mundo_ancho, mundo_alto, options) {
options = options || {};
function dibuja_karel(context, world, origen) {
// Dibujar a Karel
context.fillStyle = '#007EBE';
context.beginPath();
if (world.orientation == 0) {
// oeste
context.moveTo(origen.x, origen.y + 15);
context.lineTo(origen.x + 14, origen.y + 1);
context.lineTo(origen.x + 14, origen.y + 8);
context.lineTo(origen.x + 28, origen.y + 8);
context.lineTo(origen.x + 28, origen.y + 22);
context.lineTo(origen.x + 14, origen.y + 22);
context.lineTo(origen.x + 14, origen.y + 29);
} else if (world.orientation == 1) {
// norte
context.moveTo(origen.x + 1, origen.y + 14);
context.lineTo(origen.x + 15, origen.y);
context.lineTo(origen.x + 29, origen.y + 14);
context.lineTo(origen.x + 22, origen.y + 14);
context.lineTo(origen.x + 22, origen.y + 28);
context.lineTo(origen.x + 8, origen.y + 28);
context.lineTo(origen.x + 8, origen.y + 14);
} else if (world.orientation == 2) {
// este
context.moveTo(origen.x + 2, origen.y + 8);
context.lineTo(origen.x + 17, origen.y + 8);
context.lineTo(origen.x + 17, origen.y + 1);
context.lineTo(origen.x + 30, origen.y + 15);
context.lineTo(origen.x + 17, origen.y + 29);
context.lineTo(origen.x + 17, origen.y + 22);
context.lineTo(origen.x + 2, origen.y + 22);
} else if (world.orientation == 3) {
// sur
context.moveTo(origen.x + 8, origen.y + 2);
context.lineTo(origen.x + 22, origen.y + 2);
context.lineTo(origen.x + 22, origen.y + 17);
context.lineTo(origen.x + 29, origen.y + 17);
context.lineTo(origen.x + 15, origen.y + 30);
context.lineTo(origen.x + 1, origen.y + 17);
context.lineTo(origen.x + 8, origen.y + 17);
}
context.closePath();
context.fill();
}
context.clearRect(0, 0, mundo_ancho, mundo_alto);
context.fillStyle = '#e6e6e6';
context.fillRect(0, 0, mundo_ancho, mundo_alto);
var tamanio_lienzo = { x: mundo_ancho - 30, y: mundo_alto - 30 };
var tamanio_mundo = { x: mundo_ancho, y: mundo_alto };
context.fillStyle = options.editable ? '#FFFFFF' : '#FAFAFA';
context.fillRect(30, 0, tamanio_lienzo.x, tamanio_lienzo.y);
// Coordenada para dibujar la primera casilla
var origen = { x: 30, y: mundo_alto - 60 };
this.num_columnas =
(tamanio_lienzo.x / 30 + Math.ceil((tamanio_lienzo.x % 30) / 30)) * 1;
this.num_filas =
(tamanio_lienzo.y / 30 + Math.ceil((tamanio_lienzo.y % 30) / 30)) * 1;
if (options.track_karel) {
// Rastrea la ubicación de karel y lo forza a aparecer
if (world.i < this.primera_fila) {
this.primera_fila = Math.floor(world.i);
} else if (world.i > this.primera_fila + this.num_filas - 2) {
this.primera_fila = Math.floor(world.i - this.num_filas) + 3;
}
if (world.j < this.primera_columna) {
this.primera_columna = Math.floor(world.j);
} else if (world.j > this.primera_columna + this.num_columnas - 2) {
this.primera_columna = Math.floor(world.j - this.num_columnas) + 3;
}
}
// Cuadrados de las esquinas
for (var i = 0; i < this.num_filas; i++) {
for (var j = 0; j < this.num_columnas; j++) {
x = origen.x + 30 * j;
y = origen.y - 30 * i;
context.fillStyle = '#818181';
context.fillRect(x - 2, y + 26, 6, 6);
}
}
// Dibujar las cosas que pertenecen al mundo por cada casilla
num_fila = 1; // Posicion relativa a la pantalla
num_columna = 1; // Posicion relativa a la pantalla
for (
var fila = this.primera_fila;
fila < this.primera_fila + this.num_filas;
fila++
) {
num_columna = 1;
for (
var columna = this.primera_columna;
columna < this.primera_columna + this.num_columnas;
columna++
) {
// Si esa casilla se debe imprimir
if (options.editable) {
context.fillStyle = '#eee';
if (world.getDumpCell(fila, columna)) {
context.fillRect(
origen.x + (num_columna - 1) * 30 + 4,
origen.y - (num_fila - 1) * 30 + 2,
24,
24,
);
}
}
// Dibujar a karel
if (world.i === fila && world.j === columna) {
var referencia = {
x: origen.x + (num_columna - 1) * 30,
y: origen.y - (num_fila - 1) * 30,
};
dibuja_karel(context, world, referencia);
}
// Paredes
context.fillStyle = '#191919';
var paredes = world.walls(fila, columna);
if ((paredes & 0x1) != 0) {
// oeste
context.fillRect(
origen.x + (num_columna - 1) * 30 - 1,
origen.y - (num_fila - 1) * 30,
4,
30,
);
}
if ((paredes & 0x2) != 0) {
// norte
context.fillRect(
origen.x + (num_columna - 1) * 30 + 1,
origen.y - (num_fila - 1) * 30 + 27 - 30,
30,
4,
);
}
if ((paredes & 0x4) != 0) {
// este
context.fillRect(
origen.x + (num_columna - 1) * 30 - 1 + 30,
origen.y - (num_fila - 1) * 30,
4,
30,
);
}
if ((paredes & 0x8) != 0) {
// oeste
context.fillRect(
origen.x + (num_columna - 1) * 30 + 1,
origen.y - (num_fila - 1) * 30 + 27,
30,
4,
);
}
// Zumbadores
var zumbadores = world.buzzers(fila, columna);
if (zumbadores == -1 || zumbadores > 0) {
context.fillStyle = options.editable ? '#00FF00' : '#E0E0E0';
if (zumbadores == -1) {
context.fillRect(
origen.x + (num_columna - 1) * 30 + 8,
origen.y - (num_fila - 1) * 30 + 8,
16,
12,
);
context.font = '25px monospace';
context.fillStyle = '#000000';
context.fillText(
'∞',
origen.x + (num_columna - 1) * 30 + 9,
origen.y - (num_fila - 1) * 30 + 23,
);
} else if (zumbadores < 10) {
context.fillRect(
origen.x + (num_columna - 1) * 30 + 9,
origen.y - (num_fila - 1) * 30 + 8,
12,
14,
);
context.font = '12px monospace';
context.fillStyle = '#000000';
context.fillText(
String(zumbadores),
origen.x + (num_columna - 1) * 30 + 11,
origen.y - (num_fila - 1) * 30 + 20,
);
} else {
context.fillRect(
origen.x + (num_columna - 1) * 30 + 7,
origen.y - (num_fila - 1) * 30 + 8,
16,
14,
);
context.font = '12px monospace';
context.fillStyle = '#000000';
context.fillText(
String(zumbadores),
origen.x + (num_columna - 1) * 30 + 8,
origen.y - (num_fila - 1) * 30 + 20,
);
}
}
num_columna++;
}
num_fila++;
}
this.should_draw = !this.should_draw;
// Numeros de fila
var a = 1;
for (i = this.primera_fila; i < this.primera_fila + this.num_filas; i++) {
context.font = '14px monospace';
context.fillStyle = '#000000';
context.fillText('' + i, 10, mundo_alto - (10 + a * 30));
a++;
}
// Numeros de colummna
a = 1;
for (
i = this.primera_columna;
i < this.primera_columna + this.num_columnas;
i++
) {
context.font = '14px monospace';
context.fillStyle = '#000000';
context.fillText('' + i, 10 + 30 * a, mundo_alto - 10);
a++;
}
if (typeof document !== 'undefined') {
document.getElementById('mochila').value = world.bagBuzzers;
}
if (this.polygon) {
context.fillStyle = '#ff0000';
var from_x =
origen.x + (this.polygon_begin[1] - this.primera_columna) * 30;
var from_y = origen.y - (this.polygon_begin[0] - this.primera_fila) * 30;
var width = 4;
var height = 4;
// corner marker
context.fillRect(from_x - 2, from_y + 26, 6, 6);
if (this.polygon_end) {
context.fillStyle = '#007EBE';
if (this.polygon_begin[0] == this.polygon_end[0]) {
width = 30 * (this.polygon_end[1] - this.polygon_begin[1]);
} else {
height = 30 * (this.polygon_begin[0] - this.polygon_end[0]);
}
context.fillRect(from_x - 1, from_y + 27, width, height);
}
}
};
this.polygonStart = function (fila, columna) {
this.polygon = !(
this.polygon_begin &&
this.polygon_begin[0] == fila &&
this.polygon_begin[1] == columna
);
if (this.polygon) {
this.polygon_begin = [fila, columna];
} else {
this.polygon_begin = undefined;
}
};
this.polygonUpdate = function (fila, columna) {
// debe compartir alguna coordenada pero no las dos
if ((this.polygon_begin[0] == fila) ^ (this.polygon_begin[1] == columna)) {
this.polygon_end = [fila, columna];
} else {
this.polygon_end = undefined;
}
};
this.polygonFinish = function (fila, columna) {
this.polygonUpdate(fila, columna);
if (this.polygon_end) {
var result = {
start_row: Math.min(this.polygon_begin[0], this.polygon_end[0]),
finish_row: Math.max(this.polygon_begin[0], this.polygon_end[0]),
start_column: Math.min(this.polygon_begin[1], this.polygon_end[1]),
finish_column: Math.max(this.polygon_begin[1], this.polygon_end[1]),
};
this.polygonClear();
return result;
} else {
return null;
}
};
this.polygonClear = function () {
this.polygon_begin = this.polygon_end = undefined;
this.polygon = false;
};
this.hoverRuler = function (fila, columna, mundo_ancho, mundo_alto) {
// Coordenada para dibujar la primera casilla
var origen = { x: 30, y: mundo_alto - 60 };
context.fillStyle = 'rgba(255,0,0,0.4)';
// pinta de rojo sobre la zona gris
context.fillRect(
6,
origen.y - (fila - this.primera_fila) * 30 + 3,
this.tamano_celda - 6,
this.tamano_celda - 6,
);
context.fillRect(
origen.x + (columna - this.primera_columna) * 30 + 3,
origen.y + 30,
this.tamano_celda - 6,
this.tamano_celda - 4,
);
};
this.hoverCorner = function (fila, columna, mundo_ancho, mundo_alto) {
// Coordenada para dibujar la primera casilla
var origen = { x: 30, y: mundo_alto - 60 };
context.fillStyle = 'rgba(255,0,0,0.5)';
context.fillRect(
origen.x + (columna - this.primera_columna) * 30 - 4,
origen.y - (fila - this.primera_fila) * 30 + 24,
10,
10,
);
this.hoverRuler(fila, columna, mundo_ancho, mundo_alto);
};
this.hoverWall = function (
fila,
columna,
orientacion,
mundo_ancho,
mundo_alto,
) {
// Coordenada para dibujar la primera casilla
var origen = { x: 30, y: mundo_alto - 60 };
context.fillStyle = 'rgba(255,0,0,0.5)';
if (orientacion == 0) {
// oeste
context.fillRect(
origen.x + (columna - this.primera_columna) * 30 - 2,
origen.y - (fila - this.primera_fila) * 30 + 2,
6,
24,
);
} else if (orientacion == 1) {
// norte
context.fillRect(
origen.x + (columna - this.primera_columna) * 30 + 4,
origen.y - (fila - this.primera_fila) * 30 - 4,
24,
6,
);
} else if (orientacion == 2) {
// este
context.fillRect(
origen.x + (columna - this.primera_columna) * 30 - 2 + 30,
origen.y - (fila - this.primera_fila) * 30 + 2,
6,
24,
);
} else if ((orientacion = 3)) {
// sur
context.fillRect(
origen.x + (columna - this.primera_columna) * 30 + 4,
origen.y - (fila - this.primera_fila) * 30 + 26,
24,
6,
);
}
this.hoverRuler(fila, columna, mundo_ancho, mundo_alto);
};
this.hoverBuzzer = function (fila, columna, mundo_ancho, mundo_alto) {
// Coordenada para dibujar la primera casilla
var origen = { x: 30, y: mundo_alto - 60 };
context.fillStyle = 'rgba(255,0,0,0.5)';
context.fillRect(
origen.x + (columna - this.primera_columna) * 30 + 4,
origen.y - (fila - this.primera_fila) * 30 + 2,
this.tamano_celda - 6,
this.tamano_celda - 6,
);
this.hoverRuler(fila, columna, mundo_ancho, mundo_alto);
};
this.moveSouth = function () {
if (this.primera_fila > 1) this.primera_fila--;
};
this.moveNorth = function () {
if (this.primera_fila + this.num_filas - 2 < worldHeight)
this.primera_fila++;
};
this.moveWest = function () {
if (this.primera_columna > 1) this.primera_columna--;
};
this.moveEast = function () {
if (this.primera_columna + this.num_columnas - 2 < worldWidth)
this.primera_columna++;
};
this.calculateCell = function (x, y) {
mx = Math.max(x + this.margin, this.tamano_celda);
my = Math.max(y + this.margin, this.tamano_celda);
var column = Math.floor(mx / this.tamano_celda) + this.primera_columna - 1;
column = Math.min(column, this.maxColumns + 1);
var row = Math.floor(my / this.tamano_celda) + this.primera_fila - 1;
row = Math.min(row, this.maxRows + 1);
var x_in_wall = Math.floor((mx / this.margin) % 4) < 2;
var y_in_wall = Math.floor((my / this.margin) % 4) < 2;
var kind = Kind.Beeper;
if (x_in_wall && y_in_wall) kind = Kind.Corner;
else if (x_in_wall) kind = Kind.WestWall;
else if (y_in_wall) kind = Kind.SouthWall;
return { row: row, column: column, kind: kind, x: x, y: y };
};
};
if (typeof exports !== 'undefined') {
exports.WorldRender = WorldRender;
exports.Kind = Kind;
}