_ _    _ _____  ___   __                       
 __      _(_) | _(_)___ / ( _ ) / /_   ___ ___  _ __ ___  
 \ \ /\ / / | |/ / | |_ \ / _ \| '_ \ / __/ _ \| '_ ` _ \ 
  \ V  V /| |   <| |___) | (_) | (_) | (_| (_) | | | | | |
   \_/\_/ |_|_|\_\_|____/ \___/ \___(_)___\___/|_| |_| |_|

User:Writ Keeper/Scripts/freecell.js

In today's world, User:Writ Keeper/Scripts/freecell.js has become a topic of great importance and interest to a wide variety of people. Whether it's a cultural phenomenon, a historical figure, or a contemporary concept, User:Writ Keeper/Scripts/freecell.js has captured the attention of experts, enthusiasts, and scholars alike. Its impact extends to different aspects of modern life, from politics and economics to popular culture and society in general. In this article, we will explore in depth the meaning and relevance of User:Writ Keeper/Scripts/freecell.js, analyzing its origins, its evolution over time and its influence on the world today.
//only do anything if on the freecell homepage
if (mw.config.get("wgPageName") == "User:Writ_Keeper/freecell")
{
	//Global state variables
	var gameState = null;
	var pastGameStates = ;
	var selectedCards = {cards:,sourceIndex:null,sourceType:null};
	
	function deal() 
	{
		gameState = {freecells:,columns:, dirty:false},{cards:, dirty:false},{cards:, dirty:false},{cards:, dirty:false},{cards:, dirty:false},{cards:, dirty:false},{cards:, dirty:false},{cards:, dirty:false}],homecells:};
		pastGameStates = ;
		let rng = window.crypto || window.msCrypto;
		let deckSize = 52;
		let rngArray = new Uint16Array(deckSize);
		let rejectArray = new Uint16Array(1);
		let maxInt = 65536;
		deck = new Array(deckSize);
		for(i = 0; i < deck.length; i++)
		{
			deck = i;
		}
		rng.getRandomValues(rngArray);
		for(i=(deck.length - 1); i >= 1; i--)
		{
			//discard values greater than the maximum multiple of i+1 below maxInt; these values would skew the distribution
			while(rngArray >= Math.floor(maxInt/(i+1)) * (i+1))
			{
				rng.getRandomValues(rejectArray);
				rngArray = rejectArray;
			}
			let tempStorage = deck;
			let randomIndex = rngArray%(i+1);
			deck = deck;
			deck = tempStorage;
			deckSize--;
		}
		cardIndex = 0;
		//now deck is shuffled, deal
		for(i = 0; i < 4; i++)
		{
			for(j = 0; j < 7; j++)
			{
				addCardToColumn(getCardFromDeck(cardIndex), i);
				cardIndex++;
			}
		}
		for(i = 0; i < 4; i++)
		{
			for(j = 0; j < 6; j++)
			{
				addCardToColumn(getCardFromDeck(cardIndex), i);
				cardIndex++;
			}
		}
		for(columnIndex = 0; i < 8; i++)
		{
			let columnLength = gameState.columns.length;
			let previousCard = gameState.columns.cards;
			for(index = columnLength - 2; index >= 0; index--) 
			{
				let nextCard = gameState.columns.cards;
				if(allPrevInOrder && nextCard.rank == previousCard.rank + 1 && true /* TODO: make sure suits are alternating*/)
				{
					nextCard.inOrder = true;
					previousCard = nextCard;
				}
				else
				{
					nextCard.inOrder = false;
					allPrevInOrder = false;
				}
			}
		}
	}
	function updateGameDisplay(forceRefresh) 
	{
		for(let i = 0; i < 4; i++)
		{
			if(forceRefresh || gameState.freecells.dirty)
			{
				updateFreecell(i);
			}
		}
		for(let i = 0; i < 4; i++)
		{
			if(forceRefresh || gameState.homecells.dirty)
			{
				updateHomecell(i);
			}
		}
		for(let i = 0; i < 8; i++)
		{
			if(forceRefresh || gameState.columns.dirty)
			{
				updateColumn(i);
			}
		}
	}
	function updateFreecell(index)
	{
		updateCellVisual(gameState.freecells.card, index, "freecell");
		gameState.freecells.dirty = false;
	}
	function updateHomecell(index)
	{
		updateCellVisual(gameState.homecells.card, index, "homecell");
		gameState.homecells.dirty = false;		
	}
	function updateCellVisual(card, index, idName) 
	{
		if(card == null)
		{
			$("#" + idName + index).attr("class","emptySpace");
		}
		else
		{
			$("#" + idName + index).attr("class","fullCard");
			let coords = getCardBackground(card);
			$("#" + idName + index).css("background-position", ""+ coords.x + "px " + coords.y + "px");
		}
	}
	function updateColumn(index)
	{
		let column = gameState.columns;
		if(column.cards == null || column.cards.length == 0)
		{
			$("#column" + index).html('<div class="emptyCard" style="display:inline-block; width:97px; height:139px; border-radius:3px; background-color:#044905; border:1px dotted"></div>');
		}
		else 
		{
			$("column" + index).empty();
			let hiddenCards = column.cards.length - 1;
			let coords = null;
			for(let i = 0; i < hiddenCards; i++)
			{
				$("#column" + index).append('<div class="hiddenCard" id="col' + index + 'card'+i+'" style="display:inline-block; width:97px; height:139px; border-radius:3px; background-color:#044905; border:1px dotted"></div>');
				coords = getCardBackground(column.cards);
				$("#col"+index+"card"+i).css("background-position", ""+ coords.x + "px " + coords.y + "px");
			}
			$("#column" + index).append('<div class="fullCard" id="col' + index + 'card'+hiddenCards+'" style="display:inline-block; width:97px; height:139px; border-radius:3px; background-color:#044905; border:1px dotted"></div>');
			coords = getCardBackground(column.cards);
			$("#col"+index+"card"+hiddenCards).css("background-position", ""+ coords.x + "px " + coords.y + "px");
		}
		gameState.columns.dirty = false;
	}
	function AttemptCardMove(destIndex, destType) 
	{
		if(selectedCards == null || selectedCards.length == 0)
		{
			console.log("attempted to move zero cards");
			return false;
		}
		if(destType == "homecell" || destType == "freecell")
		{
			if(selectedCards.length > 1)
			{
				alert("Tried to move more than one card into a " + destType + "!");
				return false;
			}
			//special case; automatically send card to its proper homecell on doubleclick
			if(destIndex == null && destType == "homecell") 
			{
				let i = 0;
				
				//if it's an ace we're trying to move, search for an empty homecell
				if(selectedCards.rank == 1)
				{
					while(i < 4 && gameState.homecell.card != null)
					{
						i++;
					}
					if(i >= 4)
					{
						alert("No open homecells for ace (this shouldn't happen)");
						return false;
					}
					moveCards(i, "homecell");
					return true;
				}
				else
				{
				//otherwise, search for the homecell of correct suit and see if the ranks are correct
					let card = null;
					while(i < 4 && (card == null || card.suit != selectedCards.suit))
					{
						i++;
					}
					if(i >= 4)
					{
						//ran off the end, just deselect and return quietly
						deselectCards();
						return false;
					}
					else
					{
						if(
					}
				}
			}
		}
	}
	function addCardToColumn(card, columnIndex)
	{
		gameState.columns.push(card);
		card.inOrder = true;		
	}
	function removeCardFromColumn()
	{
	}
	function getCardFromDeck(index)
	{
		var cardIndex = deck;
		return {"suit": ((Math.floor(cardIndex/13)%4)+1),"rank":(cardIndex%13 + 1), "inOrder": true};
	}
	function getCardBackground(card)
	{
		var cardBackground = {"x":0,"y":0};
		switch (card.rank)
		{
			case 1:
				cardBackground.x = -1;
				break;
			case 2:
				cardBackground.x = -100;
				break;
			case 3:
				cardBackground.x = -199;
				break;
			case 4:
				cardBackground.x = -298;
				break;
			case 5:
				cardBackground.x = -396;
				break;
			case 6:
				cardBackground.x = -495;
				break;
			case 7:
				cardBackground.x = -593;
				break;
			case 8:
				cardBackground.x = -691;
				break;
			case 9:
				cardBackground.x = -790;
				break;
			case 10:
				cardBackground.x = -888;
				break;
			case 11:
				cardBackground.x = -987;
				break;
			case 12:
				cardBackground.x = -1085;
				break;
			case 13:
				cardBackground.x = -1184;
				break;
			default:
				cardBackground.x = -199;
		}
		
		switch (card.suit)
		{
			case 1:
			case 2:
			case 3:
			case 4:
				cardBackground.y = (-2+-143*(card.suit-1));
				break;
			default:
				cardBackground.y = -574;
		}
		return cardBackground;
	}
	function addToCount(card, currentTotal)
	{
		switch(card.rank)
		{
			case 2:
			case 3:
			case 4:
			case 5:
			case 6:
			case 7:
			case 8:
			case 9:
				if(currentTotal.count + card.rank > 21 && currentTotal.softAce == true)
				{
					currentTotal.softAce = false;
					currentTotal.count = currentTotal.count - 10 + card.rank ;
				}
				else currentTotal.count += card.rank ;
				break;
			case 10:
			case 11:
			case 12:
			case 13:
				if(currentTotal.count + 10 > 21 && currentTotal.softAce == true)
				{
					currentTotal.softAce = false;
				}
				else currentTotal.count += 10;
				break;
			case 1:
				if(currentTotal.count + 11 > 21)
				{
					currentTotal.count += 1;
				}
				else
				{
					currentTotal.count += 11;
					currentTotal.softAce = true;
				}
		}
		
	}
	$(document).ready(prepareBlackjack);
}