办公室的XP所有内置的游戏全部被策略禁止,自己写个空当接龙自娱自乐吧!(上班时间就不要啦)
正在学jQuery,真是好东西,把大部分繁琐的事情都搞定了,写起javascript畅快多了,就用它吧。
不想花太多时间来制作扑克牌,就直接html+css搞定,于是没有使用任何图片,简单的牌面,只是利用border做了牌的斜角,收牌时加了一点动画效果。
需jquery1.5以上版本
最终效果:
css
View Code
#freecell{background:#fff;cursor:default;padding:5px;background:#fff;text-align:center;font-size:12px;font-family:Arial;}
#fc-body{width:660px;}
#fc-toolbar{margin:0 0 5px 1px;text-align:left;}
.fc-buttons a:link,.fc-buttons a:visited{width:auto !important;width:50px;min-width:50px;padding:1px 5px;text-align:center;margin:2px 5px;border:1px #06c solid;display:inline-block;text-decoration:none;color:#06c;background:#fff;}
.fc-buttons a:hover{color:#fff;background:#06c;}
#fc-table{clear:left;float:left;border:1px #eee solid;height:auto !important;height:364px;min-height:364px;}
.fc-column{float:left;width:80px;text-align:center;padding:90px 0px;}
.fc-card{width:64px;text-align:left;background-color:#fff;position:relative;}
.fc-column .fc-card{margin-top:-78px;}
#fc-cells{margin-right:10px;}
.fc-cell{width:64px;border:1px #666 solid;height:103px;margin:2px;float:left;padding:1px;}
#fc-info{width:64px;border-style:none;font-size:40px;text-align:left;float:left;}
#fc-logo span{display:block;padding:0 5px;margin:-30px 0;}
#fc-logo span.fc-top{margin-top:-10px !important;margin-top:-5px;}
#fc-logo span.fc-down{margin-bottom:-10px;}
#fc-score{font-weight:bold;font-size:10px;color:#06c;margin-top:10px !important;margin-top:6px;}
#fc-score span{width:26px;display:inline-block;text-align:right;}
#fc-score span.fc-label{width:30px;}
#fc-time{clear:left;margin-bottom:5px;}
#fc-time span{width:auto !important;width:30px;min-width:30px;display:inline-block;text-align:right;margin-right:40px;}
#fc-time span.fc-label{font-weight:bold;width:65px;margin-right:5px;}
.fc-animate{position:absolute;}
.fc-right{text-align:right;}
.fc-card-content{border:1px #666 solid;border-style:none solid;}
.fc-card h2{font-size:16px;padding:0 1px;margin:0;}
.fc-card h2 span{display:block;font-size:16px !important;margin-top:-7px !important;margin-top:0;font-size:11px;padding:2px 0;}
.fc-red{color:red;}
.fc-black{color:black;}
.fc-card .fc-card-pattern{font-size:40px !important;font-size:22px;text-align:center;height:36px !important;height:19px;margin-top:-12px !important;;margin-top:0;overflow:hidden;}
.fc-card-border-1,.fc-card-border-2,.fc-card-border-3,.fc-card-border-4{margin:0 1px;height:1px;border:1px #666 solid;border-style:none solid;overflow:hidden;}
.fc-card-border-2{margin:0 2px;}
.fc-card-border-3{margin:0 3px;}
.fc-card-border-4{margin:0 4px;border-style:none;border-top:1px #666 solid;}
.fc-select,.fc-select .fc-card-border-1,.fc-select .fc-card-border-2,.fc-select .fc-card-border-3,.fc-select .fc-card-border-4{background:#3ff;color:#fff;}
#fc-highlight{position:absolute;z-index:10000;}
#fc-msgbox{width:220px;margin:-40px 0 0 -110px;left:50%;top:50%;position:absolute;border:1px #666 solid;background:#fff;display:none;z-index:1000;}
#fc-msgbox-title{background:#ccc;text-align:left;}
#fc-msgbox-content{padding:10px;border:1px #ccc solid;}
#fc-msgbox-buttons{text-align:center;padding:5px;}
#fc-msgbox-buttons input{width:60px;margin:0 5px;}
#fc-mask{width:100%;height:100%;top:0;left:0;position:absolute;background:#fff;filter:alpha(opacity=50);opacity:0.5;display:none;z-index:100;}
#mine td{width:18px;height:18px;border:1px #666 solid;text-align:center;background:#f0f0f0;overflow:hidden;display:block;overflow:hidden;font-size:16px;padding:0;border-color:#fff #666 #666 #fff;cursor:default;}
列中的扑克牌使用relative定位,margin-top设为负值形成牌面叠加效果。
js
$(function(){
Freecell.Initialize();
});
var Freecell={
Initialize:function(){
Animate.Init();
document.body.oncontextmenu=function(){return false;};
var fc=$('<div id="freecell">');
$(document.body).append(fc);
this.body=$('<div id="fc-body">');
fc.append(this.body);
this.toolbar=$('<div id="fc-toolbar" class="fc-buttons">');
this.body.append(this.toolbar);
this.startButton=$('<a id="fc-toolbar-start" href="javascript:void(0)">Start</a>');
this.toolbar.append(this.startButton);
this.oprZone=$('<div id="fc-oprzone">');
this.body.append(this.oprZone);
this.cellContainer=$('<div id="fc-cells">');
this.oprZone.append(this.cellContainer);
this.info=$('<div id="fc-info"><div id="fc-logo"><span class="fc-top">♠</span><span class="fc-right fc-red">♦</span><span>♣</span><span class="fc-right fc-down fc-red">♥</span></div></div>');
this.oprZone.append(this.info);
var scoreBoard=$('<div id="fc-score"><span class="fc-label">Won:</span></div>');
this.info.append(scoreBoard);
this.scoreWin=$('<span>').text(0);
scoreBoard.append(this.scoreWin).append('<br/><span class="fc-label">Lost:</span>');
this.scoreLose=$('<span>').text(0);
scoreBoard.append(this.scoreLose);
this.collectContainer=$('<div id="fc-collections">');
this.oprZone.append(this.collectContainer);
var time=$('<div id="fc-time"><span class="fc-label">Best Time:</span></div>');
this.body.append(time);
this.best=$('<span>').text('-');
time.append(this.best).append('<span class="fc-label">Time:</span>');
this.elapseTime=$('<span>').text('-');
time.append(this.elapseTime);
this.table=$('<div id="fc-table">');
this.body.append(this.table);
this.msgbox=$('<div id="fc-msgbox">');
this.body.append(this.msgbox);
this.msgboxTitle=$('<div id="fc-msgbox-title">');
this.msgbox.append(this.msgboxTitle);
this.msgboxTitle.append($('<span class="fc-black">♠</span><span class="fc-red">♦</span><span class="fc-black">♣</span><span class="fc-red">♥</span>'));
this.msgboxContent=$('<div id="fc-msgbox-content">');
this.msgbox.append(this.msgboxContent);
this.msgboxButtons=$('<div id="fc-msgbox-buttons" class="fc-buttons">');
this.msgbox.append(this.msgboxButtons);
this.msgboxButtonOK=$('<a>').text('OK').attr('href','javascript:void(0)');
this.msgboxButtons.append(this.msgboxButtonOK);
this.msgboxButtonRetry=$('<a>').text('Play again?').attr('href','javascript:void(0)');
this.msgboxButtons.append(this.msgboxButtonRetry);
this.msgboxButtonCancel=$('<a>').text('Cancel').attr('href','javascript:void(0)');
this.msgboxButtons.append(this.msgboxButtonCancel);
this.mask=$('<div id="fc-mask">');
this.body.append(this.mask);
this.availableCells=0;
this.freeColumns=0;
this.finished=true;
this.cells=[];
this.collectCells=[];
this.columns=[];
for(var i=0;i<4;i++){
this.cells[i]=new Cell(i);
this.cellContainer.append(this.cells[i].Element);
this.collectCells[i]=new CollectCell(i);
this.collectContainer.append(this.collectCells[i].Element);
}
for(var i=0;i<8;i++){
this.columns[i]=new Column(i);
this.table.append(this.columns[i].Element);
}
this.win=0;
this.lose=0;
this.bestTime=Number.MAX_VALUE;
this.timer;
this.elapse=0;
this.highlight=$('<div id="fc-highlight">');
this.body.append(this.highlight);
this.functionBind();
//this.start();
},
shuffle:function(){
this.finished=false;
this.availableCells=5;
var shuffleCards=[];
for(var i=0;i<4;i++){
this.cells[i].Destroy();
this.collectCells[i].Destroy();
for(var j=0;j<13;j++){
var cardIndex=i*13+j;
var card=new Card(i,j+1);
shuffleCards[cardIndex]=card;
}
}
for(var i=0;i<8;i++){
var col=this.columns[i];
col.Destroy();
var q=6;
if(i<4){
q=7;
}
for(var j=0;j<q;j++){
var l=shuffleCards.length-1;
var rnd=Math.round(Math.random()*l);
col.Add(shuffleCards[rnd]);
shuffleCards.splice(rnd,1);
}
}
},
score:function(){
this.scoreWin.text(this.win);
this.scoreLose.text(this.lose);
},
start:function(){
Freecell.shuffle();
Freecell.startTimer();
},
disableButton:function(disable){
if(this.finished){
if(disable){
this.mask.show();
this.msgboxButtons.hide();
}else{
this.msgboxButtons.show();
}
}
},
startTimer:function(){
this.elapse=0;
this.setRealTime();
this.timer=setInterval(this.timerInterval,1000);
},
timerInterval:function(){
Freecell.elapse++;
Freecell.setRealTime();
},
getTimeValue:function(){
var h=Math.floor(this.elapse/3600);
var m=Math.floor((this.elapse%3600)/60);
var s=this.elapse%60;
return (h>0?h+':':'')+(m>9?m:'0'+m)+':'+(s>9?s:'0'+s);
},
setRealTime:function(){
Freecell.elapseTime.text(Freecell.getTimeValue());
},
stopTimer:function(){
clearInterval(Freecell.timer);
Freecell.elapseTime.text(Freecell.getTimeValue());
},
setBestTime:function(){
if(Freecell.elapse<Freecell.bestTime){
Freecell.bestTime=Freecell.elapse;
Freecell.best.text(Freecell.getTimeValue());
}
},
msg:function(message,button){
if(!button){
button=0;
}
Freecell.msgboxButtonOK.hide();
Freecell.msgboxButtonRetry.hide();
Freecell.msgboxButtonCancel.hide();
if(button==0){
Freecell.msgboxButtonOK.show();
}else{
Freecell.msgboxButtonRetry.show();
Freecell.msgboxButtonCancel.show();
}
Freecell.msgboxContent.html(message);
var box=Freecell.msgbox;
var b=$(document.body);
box.show();
},
collect:function(){
if(Freecell.activeCard){
Freecell.activeCard.Deactive();
Freecell.activeCard=null;
}
var card;
var collectSth=false;
Freecell.freeColumns=0;
Freecell.availableCells=5;
for(var i=0;i<8;i++){
if(i<4){
if(Freecell.cells[i].Card){
card=Freecell.cells[i].Card;
if(Freecell.collectableCheck(card)){
Freecell.collectCells[card.ColorIndex].Add(Freecell.cells[i].Remove());
collectSth=true;
}else{
Freecell.availableCells--;
}
}
}
if(!Freecell.columns[i].IsEmpty()){
var l=Freecell.columns[i].Cards.length;
card=Freecell.columns[i].Cards[l-1];
if(Freecell.collectableCheck(card)){
Freecell.columns[i].Cards.splice(l-1,1);
Freecell.collectCells[card.ColorIndex].Add(card);
collectSth=true;
}
}else{
Freecell.freeColumns++;
}
}
if(Freecell.collectCells[0].Number==13 && Freecell.collectCells[1].Number==13 && Freecell.collectCells[2].Number==13 && Freecell.collectCells[3].Number==13){
Freecell.stopTimer();
Freecell.setBestTime();
Freecell.finished=true;
Freecell.msg('You win!',1);
Freecell.win++;
Freecell.score();
Freecell.disableButton(true);
return;
}
if(collectSth){
Freecell.collect();
}else{
if(Freecell.availableCells==1){
for(var i=0;i<8;i++){
var col=Freecell.columns[i];
if(col.IsEmpty()){
return;
}
if(i<4){
if(Freecell.fitCheck(Freecell.cells[i].Card)){
return;
}
}
if(Freecell.fitCheck(col.Cards[col.Cards.length-1])){
return;
}
}
Freecell.stopTimer();
Freecell.finished=true;
Freecell.lose++;
Freecell.score();
Freecell.msg('You lose!',1);
Freecell.mask.show();
}
}
},
fitCheck:function(card){
if(card){
for(var j=0;j<8;j++){
if(j<4){
if(Freecell.collectCells[j].Fit(card)){
return true;
}
}
if(Freecell.columns[j].Cards.length>0 && Freecell.columns[j].Cards[Freecell.columns[j].Cards.length-1].Fit(card)){
return true;
}
}
return false;
}
return true;
},
collectableCheck:function(card){
return ((card.Number==Freecell.minCollectedNumber()+1 || card.Number<3) && card.Number==Freecell.collectCells[card.ColorIndex].Number+1);
},
minCollectedNumber:function(){
var num=15;
for(var i=0;i<4;i++){
num=Math.min(num,Freecell.collectCells[i].Number);
}
return num;
},
functionBind:function(){
this.body.click(function(){
if(Freecell.activeCard){
Freecell.activeCard.Deactive();
Freecell.activeCard=null;
}
});
this.startButton.click(function(){
if(!Freecell.finished){
if(confirm('You want to give up this match?')){
Freecell.stopTimer();
Freecell.lose++;
Freecell.score();
}else{
return;
}
}
Freecell.start();
});
$('#freecell .fc-column').click(function(e){
stopBubble(e);
var col=Freecell.columns[this.attributes['index'].value];
if(Freecell.activeCard){
if(Freecell.activeCard.Owner!==col){
Freecell.activeCard.SendTo(col,Freecell.availableCells,Freecell.freeColumns);
}
Freecell.collect();
}else{
Freecell.activeCard=col.Active();
}
});
$('#fc-cells .fc-cell').click(function(e){
stopBubble(e);
var cell=Freecell.cells[this.attributes['index'].value];
if(Freecell.activeCard){
Freecell.activeCard.SendTo(cell);
Freecell.collect();
}else{
Freecell.activeCard=cell.Active();
}
});
$('#fc-collections .fc-cell').click(function(e){
stopBubble(e);
var collectCell=Freecell.collectCells[this.attributes['index'].value];
if(Freecell.activeCard){
Freecell.activeCard.SendTo(collectCell);
Freecell.collect();
}
});
$('.fc-card').live('mousedown',function(e){
stopBubble(e);
if(e.which==3){
var t=$(this);
var h=Freecell.highlight;
var p=t.offset();
h.css('top',p.top).css('left',p.left).append(t.clone()).show();
}
}).live('mouseup',function(e){
stopBubble(e);
if(e.which==3){
Freecell.highlight.empty().hide();
}
});
this.msgboxButtonOK.click(function(){
Freecell.msgbox.hide();
});
this.msgboxButtonCancel.click(function(){
Freecell.mask.hide();
Freecell.msgbox.hide();
});
this.msgboxButtonRetry.click(function(){
Freecell.start();
Freecell.mask.hide();
Freecell.msgbox.hide();
});
}
}
function stopBubble(e){
if(e && e.stopPropagation){
e.stopPropagation();
}else{
e.cancelBubble=true;
}
}
function Column(index){
this.Name='column';
this.Index=index;
this.Element=$('<div index="'+index+'" class="fc-column">');
this.Cards=[];
}
Column.prototype.Add=function(card){
if(card){
card.Owner=this;
this.Cards.push(card);
this.Element.append(card.Element);
}
}
Column.prototype.Destroy=function(){
var l=this.Cards.length;
for(var i=0;i<l;i++){
this.Cards[i].Destroy();
this.Cards[i]=null;
}
this.Cards=[];
this.Element.empty();
}
Column.prototype.Active=function(){
if(!this.IsEmpty()){
return this.Cards[this.Cards.length-1].Active();
}
return null;
}
Column.prototype.Remove=function(){
if(!this.IsEmpty()){
return this.Cards.pop();
}
return null;
}
Column.prototype.IsEmpty=function(){
return this.Cards.length==0;
}
function Cell(index){
this.Name='cell';
this.Index=index;
this.Element=$('<div class="fc-cell" index="'+index+'">');
this.Card=null;
}
Cell.prototype.Add=function(card){
if(!this.Card && card){
card.Owner=this;
this.Card=card;
this.Element.append(card.Element);
}
}
Cell.prototype.Destroy=function(){
if(this.Card){
this.Card=this.Card.Destroy();
}
this.Element.empty();
}
Cell.prototype.Active=function(){
if(this.Card){
return this.Card.Active();
}else{
return null;
}
}
Cell.prototype.Remove=function(){
var card=this.Card;
this.Card=null;
return card;
}
Cell.prototype.IsEmpty=function(){
return this.Card==null;
}
function CollectCell(index){
this.Name='collect';
this.Index=index;
this.Number=0;
this.Element=$('<div class="fc-cell" index="'+index+'">');
this.Card=null;
}
CollectCell.prototype.Add=function(card){
if(card){
if(this.Card){
this.Card.Destroy();
}
this.Card=card;
this.Number=card.Number;
Animate.Add(this.Index,this.Element,card.Element);
}
}
CollectCell.prototype.Destroy=function(){
this.Number=0;
if(this.Card){
this.Card=this.Card.Destroy();
}
this.Element.empty();
}
CollectCell.prototype.Fit=function(card){
if(card){
if(card.Number==(this.Number+1) && card.ColorIndex==this.Index){
return true;
}
}
return false;
}
var Animate={
Init:function(){
this.items=new Array(new Array(),new Array(),new Array(),new Array());
this.isPlaying=new Array(false,false,false,false);
this.speed=0.5;
this.timer=20;
},
Add:function(index,cellEl,cardEl){
var obj=new Object();
obj.cell=cellEl;
obj.card=cardEl;
this.items[index].push(obj);
this.play(index);
},
play:function(index){
if(Animate.isPlaying[index]){
return;
}
Animate.next(index);
},
animate:function(index,obj){
var card=obj.card;
var cell=obj.cell;
var pos=card.position();
var cellPos=cell.position();
var cellTop=cellPos.top;
var cellLeft=cellPos.left;
if (Math.abs(pos.top-cellTop)>5 || Math.abs(pos.left-cellLeft)>5){
card.css('top',(cellTop+pos.top)*Animate.speed).css('left',(cellLeft+pos.left)*Animate.speed);
setTimeout(function(){Animate.animate(index,obj)},Animate.timer);
}else{
cell.empty().append(card.removeClass('fc-animate').css('top',0).css('left',0));
Animate.next(index);
}
},
next:function(index){
if(Animate.items[index].length==0){
Animate.isPlaying[index]=false;
if(!Animate.isPlaying[0] && !Animate.isPlaying[1] && !Animate.isPlaying[2] && !Animate.isPlaying[3]){
Freecell.disableButton(false);
}
return;
}
Animate.isPlaying[index]=true;
var obj=Animate.items[index].shift();
var pos=obj.card.addClass('fc-animate').position();
$(document.body).append(obj.card.css('top',pos.top).css('left',pos.left));
Animate.animate(index,obj);
}
}
function Card(colorIndex,number){
this.Index=colorIndex*13+number;
this.Number=number;
this.ColorIndex=colorIndex;
this.Owner=null;
switch(colorIndex){
case 0:
this.Pattern='♠';
this.Color='black';
break;
case 1:
this.Pattern='♦';
this.Color='red';
break;
case 2:
this.Pattern='♣';
this.Color='black';
break;
case 3:
this.Pattern='♥';
this.Color='red';
break;
}
switch(number){
case 1:
this._string='A';
break;
case 11:
this._string='J';
break;
case 12:
this._string='Q';
break;
case 13:
this._string='K';
break;
default:
this._string=number;
}
this.Element=$('<div class="fc-card fc-'+this.Color+'" index="'+this.Index+'"><div class="fc-card-border-4"></div><div class="fc-card-border-3"></div><div class="fc-card-border-2"></div><div class="fc-card-border-1"></div><div class="fc-card-content"><h2 class="fc-card-num">'+this._string+'<span>'+this.Pattern+'</span></h2><div class="fc-card-pattern">'+this.Pattern+'</div><h2 class="fc-card-num fc-right"><span>'+this.Pattern+'</span>'+this._string+'</h2></div><div class="fc-card-border-1"></div><div class="fc-card-border-2"></div><div class="fc-card-border-3"></div><div class="fc-card-border-4"></div></div>');
}
Card.prototype.Destroy=function(){
this.Index=null;
this.Number=null;
this.ColorIndex=null;
this.Owner=null;
this.Element=null;
return null;
}
Card.prototype.Fit=function(card){
if(card.Number==13 || this.Color==card.Color || this.Number!=(card.Number+1)){
return false;
}
return true;
}
Card.prototype.Active=function(){
this.Element.addClass('fc-select');
if(this.Owner){
this.Owner.ActiveCard=this;
}
return this;
}
Card.prototype.Deactive=function(){
this.Element.removeClass('fc-select');
}
Card.prototype.SendTo=function(target,availableCells,emptyCols){
var owner=this.Owner;
switch(target.Name){
case 'collect':
if(target.Fit(this)){
target.Add(owner.Remove());
}
break;
case 'column':
if(target.IsEmpty()){
emptyCols--;
}
switch(owner.Name){
case 'cell':
if(target.IsEmpty() || target.Cards[target.Cards.length-1].Fit(this)){
target.Add(owner.Remove());
}
break;
case 'column':
var length=owner.Cards.length;
var curIndex=length-1;
if(target.IsEmpty()){
while(curIndex>0){
if(!owner.Cards[curIndex-1].Fit(owner.Cards[curIndex])){
break;
}
curIndex--;
}
}else{
var l=target.Cards.length;
while(curIndex>=0){
var card=owner.Cards[curIndex];
if(target.Cards[l-1].Fit(card)){
break;
}
if(curIndex>0 && !owner.Cards[curIndex-1].Fit(card)){
curIndex=-2;
break;
}
curIndex--;
}
}
if(curIndex>-1){
var cellsNeeded=length-curIndex;
if(!target.IsEmpty()){
availableCells=emptyCols*availableCells+availableCells;
if(cellsNeeded>availableCells){
alert('You need '+cellsNeeded+' cells, only '+availableCells+' available');
return;
}
}else{
if(cellsNeeded>availableCells){
curIndex=length-availableCells;
}
}
for(var i=curIndex;i<length;i++){
target.Add(owner.Cards[curIndex]);
owner.Cards.splice(curIndex,1);
}
}
break;
}
break;
case 'cell':
if(target.IsEmpty()){
target.Add(owner.Remove());
}
break;
}
}