Klassisches Solitär

Letzte Änderung: 30.12.2017

Umgesetzte Punkte

  • JavaScript
  • Canvas 2D
  • Mouse Event Handling

Klassisches Solitär online spielen

Leider unterstützt Ihr Browser das canvas-Element nicht.


<canvas id="playground" height=50 width=50></canvas>
<script>
function showInHtml ()
{
  init();
  var playground = document.getElementById("playground");
  if (! playground.getContext('2d')) {
    document.getElementById("playgroundarea").innerHTML = "Leider unterstützt Ihr Browser das canvas-Element nicht.";
    return;
  }

  playground.onmousemove = function(event) { onMouseMove(this, event); }
  playground.onmouseout = function(event) { onMouseOut(this, event); }
  playground.onclick = function(event) { onClicked(this, event); }
  paintArea(playground);
}

window.addEventListener("DOMContentLoaded", function() {
    showInHtml();
});
</script>
  

solitaer.js

download
/**
 * @description Klassisches Solitär
 * 
 * @author Thomas Thielemann www.th-thielemann.de
 */

//! Ausgangsfeld
var m_pins = new Array();

var m_possibleMoves = 0;
var m_movealbePins = 0;
var m_previousPos = {row: -1, col: -1};
var m_source = {row: -1, col: -1};
var m_targets = new Array();
var m_undobuffer = new Array();

function init()
{
    m_pins[0] = new Array      (1, 1, 1);
    m_pins[1] = new Array      (1, 1, 1);
    m_pins[2] = new Array(1, 1, 1, 1, 1, 1, 1);
    m_pins[3] = new Array(1, 1, 1, 0, 1, 1, 1);
    m_pins[4] = new Array(1, 1, 1, 1, 1, 1, 1);
    m_pins[5] = new Array      (1, 1, 1);
    m_pins[6] = new Array      (1, 1, 1);

    m_possibleMoves = 0;
    m_movealbePins = 0;
    m_previousPos = {row: -1, col: -1};
    m_source = {row: -1, col: -1};
    m_targets = new Array();
    m_undobuffer = new Array();
    countPossibleMoves();
}

function getPossibleMoves()
{
    return m_possibleMoves;
}

function getMovealbePins()
{
    return m_movealbePins;
}

function getPinValue(row, col)
{
    if (isOutOfRange(row, col)) {
        return -2;
    }
    if (row < 2 || row > 4) {
        if (col < 2 || col > 4) {
            return -1;
        }
        return m_pins[row][col - 2];
    }
    return m_pins[row][col];      
}

function setPinValue(row, col, value)
{
    if (isOutOfRange(row, col)) {
        return;
    }
    if (row < 2 || row > 4) {
        if (col < 2 || col > 4) {
            return;
        }
        m_pins[row][col - 2] = value;
        return;
    }
    m_pins[row][col] = value;      
}

function hasMultipleTargets()
{
    return m_targets.length > 1;
}

function startMultipleTargetJump(pos)
{
    m_source = pos;
}

function stopMultipleTargetJump()
{
    m_source.row = -1;
    m_source.col = -1;
}

function isMultipleTargetJump()
{
    return m_source.row !== -1;
}


/**
 * Spielfeld zeichnen
 * @param element Canvas Element
 */
function paintArea(element)
{
    if (! element) {
        console.log("Context 2d is not supported.");
        return;
    }
    var ctx = element.getContext('2d'); 
    var size = element.height / 7;
    for (var row = 0; row < 7; ++row) {
        for (var col = 0; col < 7; ++col) {
            paintPin(ctx, size, row, col);
        }
    }              
} 

/**
 * Spielfeld zeichnen
 * @param element Canvas Element
 */
function paintPin(ctx, size, row, col)
{
    var pin = getPinValue(row, col);
    switch (pin) {
        case -2:
            break;
        case -1: // Außerhalb des Bereichs
            ctx.fillStyle = "#f2f2f2";
            ctx.fillRect(size * col, size * row, size, size);
            break;
        case 0: // No pin
            ctx.fillStyle = "#cccccc";
            ctx.fillRect(size * col, size * row, size, size);
            ctx.fillStyle = "#999999";
            ctx.beginPath();
            ctx.arc(size * col + 0.5 * size, size * row + 0.5 * size, size / 5, 0, 6.3, true);
            ctx.fill();
            ctx.closePath();
            break;
        default: // Pin set
            ctx.fillStyle = "#cccccc";
            ctx.fillRect(size * col, size * row, size, size);
            ctx.fillStyle = "#74A8D0";
            ctx.beginPath();
            ctx.arc(size * col + 0.5 * size, size * row + 0.5 * size, size / 5, 0, 6.3, true);
            ctx.fill();
            ctx.closePath();
           break;
    }
} 

function paintPinHighlighted(ctx, size, row, col)
{
    var pin = getPinValue(row, col);
    switch (pin) {
        case -2: // Out of range
        case -1: // Out of range
        case 0: // No pin
            break;
        default: // Pin set
            ctx.fillStyle = "#cccccc";
            ctx.fillRect(size * col, size * row, size, size);
            ctx.fillStyle = "#337AB7";
            ctx.beginPath();
            ctx.arc(size * col + 0.5 * size, size * row + 0.5 * size, size / 5, 0, 6.3, true);
            ctx.fill();
            ctx.closePath();
           break;
    }
}

function paintJumpTargetHighlighted(ctx, size, row, col)
{
    var pin = getPinValue(row, col);
    switch (pin) {
        case -2: // Out of range
        case -1: // Out of range
            break;
        case 0: // No pin
            ctx.fillStyle = "#cccccc";
            ctx.fillRect(size * col, size * row, size, size);
            ctx.fillStyle = "#337AB7";
            ctx.beginPath();
            ctx.arc(size * col + 0.5 * size, size * row + 0.5 * size, size / 4, 0, 6.3, true);
            ctx.fill();
            ctx.closePath();
            ctx.fillStyle = "#999999";
            ctx.beginPath();
            ctx.arc(size * col + 0.5 * size, size * row + 0.5 * size, size / 5, 0, 6.3, true);
            ctx.fill();
            ctx.closePath();
            break;
        default: // Pin set
            break;
    }
}

function showPossibleJump(canvas, event)
{
    if (isMultipleTargetJump()) {
        return;
    }
    var pos = getPinFromMousePosition(canvas, event);
    if (isOutOfRange(pos.row, pos.col)) {
        return;
    }
    if (pos.row === m_previousPos.row && pos.col === m_previousPos.col) {
        return;
    }
    var ctx = canvas.getContext('2d');   
    var size = canvas.height / 7;
    for (var i = 0; i < m_targets.length; ++i) {
        paintPin(ctx, size, m_targets[i].row, m_targets[i].col);
    }
    m_targets = [];
    paintPin(ctx, size, m_previousPos.row, m_previousPos.col);
    paintPinHighlighted(ctx, size, pos.row, pos.col);
    m_previousPos.row = pos.row;
    m_previousPos.col = pos.col;
    
    if (checkNorth(pos.row, pos.col)) {
        var targetPos = {row: pos.row - 2, col: pos.col};
        m_targets[m_targets.length] = targetPos;
        paintJumpTargetHighlighted(ctx, size, targetPos.row, targetPos.col);
    }
    if (checkEast(pos.row, pos.col)) {
        var targetPos = {row: pos.row, col: pos.col + 2};
        m_targets[m_targets.length] = targetPos;
        paintJumpTargetHighlighted(ctx, size, targetPos.row, targetPos.col);
    }
    if (checkSouth(pos.row, pos.col)) {
        var targetPos = {row: pos.row + 2, col: pos.col};
        m_targets[m_targets.length] = targetPos;
        paintJumpTargetHighlighted(ctx, size, targetPos.row, targetPos.col);
    }
    if (checkWest(pos.row, pos.col)) {
        var targetPos = {row: pos.row, col: pos.col - 2};
        m_targets[m_targets.length] = targetPos;
        paintJumpTargetHighlighted(ctx, size, targetPos.row, targetPos.col);
    }
}

function setJumpPins(ctx, size, sourceRow, sourceCol, targetRow, targetCol)
{
    var pin = getPinValue(sourceRow, sourceCol);
    var rowDirection = (targetRow - sourceRow);
    var colDirection = (targetCol - sourceCol);
    
    var undoItem = [];
    // The new position of the pin
    undoItem[0] = [sourceRow + rowDirection, sourceCol + colDirection, 0];
    setPinValue(sourceRow + rowDirection, sourceCol + colDirection, pin);
    paintPin(ctx, size, sourceRow + rowDirection, sourceCol + colDirection);

    // This pin will be removed
    rowDirection = Math.floor(rowDirection * 0.5);
    colDirection = Math.floor(colDirection * 0.5);
    undoItem[1] = [sourceRow + rowDirection, sourceCol + colDirection, getPinValue(sourceRow + rowDirection, sourceCol + colDirection)];
    setPinValue(sourceRow + rowDirection, sourceCol + colDirection, 0);
    paintPin(ctx, size, sourceRow + rowDirection, sourceCol + colDirection);

    undoItem[2] = [sourceRow, sourceCol, pin];
    setPinValue(sourceRow, sourceCol, 0);        
    paintPin(ctx, size, sourceRow, sourceCol);
    m_undobuffer[m_undobuffer.length] = undoItem;
}

function performJump(canvas, event)
{
    var pos = getPinFromMousePosition(canvas, event);
    if (isOutOfRange(pos.row, pos.col)) {
        return;
    }

    var ctx = canvas.getContext('2d');   
    var size = canvas.height / 7;
    if (isMultipleTargetJump()) {
        for (var i = 0; i < m_targets.length; ++i) {
            if (m_targets[i].row === pos.row && m_targets[i].col === pos.col) {
                setJumpPins(ctx, size, m_source.row, m_source.col, m_targets[i].row, m_targets[i].col);
                m_targets.splice(i, 1); 
                stopMultipleTargetJump();
            }
        }
        if (isMultipleTargetJump()) { // Did clicked to another pos
            paintPin(ctx, size, m_source.row, m_source.col);
            stopMultipleTargetJump();
        }
        for (var i = 0; i < m_targets.length; ++i) {
            paintPin(ctx, size, m_targets[i].row, m_targets[i].col);
        }
        m_targets = [];        
        return;
    }
    
    if (hasMultipleTargets()) {
        startMultipleTargetJump(pos);
        return;
    }
    
    if (checkNorth(pos.row, pos.col)) {
        setJumpPins(ctx, size, pos.row, pos.col, pos.row - 2, pos.col);
    }
    else if (checkEast(pos.row, pos.col)) {
        setJumpPins(ctx, size, pos.row, pos.col, pos.row, pos.col + 2);
    }
    else if (checkSouth(pos.row, pos.col)) {
        setJumpPins(ctx, size, pos.row, pos.col, pos.row + 2, pos.col);
    }
    else if (checkWest(pos.row, pos.col)) {
        setJumpPins(ctx, size, pos.row, pos.col, pos.row, pos.col - 2);
    }
}

function removeAllHighlights(canvas, event)
{
    var ctx = canvas.getContext('2d');   
    var size = canvas.height / 7;
    for (var i = 0; i < m_targets.length; ++i) {
        paintPin(ctx, size, m_targets[i].row, m_targets[i].col);
    }
    m_targets = [];
    paintPin(ctx, size, m_previousPos.row, m_previousPos.col);
    m_previousPos = {row: -1, col: -1};
    previousTargetPos = {row: -1, col: -1};
}

function getPinFromMousePosition(canvas, event)
{
    var rect = canvas.getBoundingClientRect();
    var y = Math.floor((event.clientX - rect.left) / canvas.height * 7, 0);
    var x = Math.floor((event.clientY - rect.top) / canvas.height * 7, 0);
    return {row: x, col: y};
}

function isOutOfRange(row, col)
{ 
    return (row < 0 || row > 6 || col < 0 || col > 6);
}
    
function checkNorth(row, col)
{
    return (getPinValue(row, col) > 0) && (getPinValue(row - 1, col) > 0) && (getPinValue(row - 2, col) === 0);
}
function checkEast(row, col)
{
    return (getPinValue(row, col) > 0) && (getPinValue(row, col + 1) > 0) && (getPinValue(row, col + 2) === 0);
}
function checkSouth(row, col)
{
    return (getPinValue(row, col) > 0) && (getPinValue(row + 1, col) > 0) && (getPinValue(row + 2, col) === 0);
}
function checkWest(row, col)
{
    return (getPinValue(row, col) > 0) && (getPinValue(row, col - 1) > 0) && (getPinValue(row, col - 2) === 0);
}

function countPossibleMoves()
{
    m_possibleMoves = 0;
    m_movealbePins = 0;
    for (var row = 0; row < 7; ++row) {
        for (var col = 0; col < 7; ++col) {
            if (getPinValue(row, col) > 0) {
                var oldPossibleMoves = m_possibleMoves;
                if (checkNorth(row, col)) {
                    ++m_possibleMoves;
                }
                if (checkEast(row, col)) {
                    ++m_possibleMoves;
                }
                if (checkSouth(row, col)) {
                    ++m_possibleMoves;
                }
                if (checkWest(row, col)) {
                    ++m_possibleMoves;
                }
                if (oldPossibleMoves !== m_possibleMoves) {
                    ++m_movealbePins;
                }
            }
        }
    } 
}

function undoLastJump(canvas)
{
    if (m_undobuffer.length === 0) {
        return;
    }
    var ctx = canvas.getContext('2d');   
    var size = canvas.height / 7;
    var undoItem = m_undobuffer.pop();    
    for (var i = 0; i < undoItem.length; ++i) {
        setPinValue(undoItem[i][0], undoItem[i][1], undoItem[i][2]);
        paintPin(ctx, size, undoItem[i][0], undoItem[i][1]);
    }
}




© 2003-2018 th-thielemann.de