I'm writing code for a blackjack game and have run into some problems. I have written two functions: one for the initial deal and one for each consecutive hit. this is the deal function:
var deck = [1,2,3,4,5,6,7,8,9,10,"Jack","Queen","King","Ace"];
function deal() {
var card1_val = Math.floor(Math.random() * deck.length);
var card2_val = Math.floor(Math.random() * deck.length);
var card1 = deck[card1_val];
var card2 = deck[card2_val];
var hand = card1 + ", " + card2;
{//card1 Conditionals
if (card1 == "Jack") {
card1_val = 10;
}
else if (card1 == "Queen") {
card1_val = 10;
}
else if (card1 == "King") {
card1_val = 10;
}
else if (card1 == "Ace") {
card1_val = 11;
}
}
{//card2 Conditionals
if (card2 == "Jack") {
card2_val = 10;
}
else if (card2 == "Queen") {
card2_val = 10;
}
else if (card2 == "King") {
card2_val = 10;
}
else if (card2 == "Ace") {
card2_val = 11;
}
}
var res = card1_val + card2_val;
document.getElementById("result").innerHTML = hand;
//document.getElementById("test").innerHTML = card1_val + ", " + card2_val;
if (res > 21) {
alert("Blackjack!");
}
}
This is the hit function:
function hit() {
var card_val = Math.floor(Math.random() * deck.length);
var nhand = deck[card_val];
bucket = hand + nhand
}
If you look at hit() I am using the var hand from deal(). I can't make it global because I need the value to be a fresh random each time. How do I access this same variable without rewriting lines of code? Any help would be appreciated.
You can either
Declare hand outside of the function scope with just var hand; and use hand in the deal function without redeclaring it as a var;
Or use window.hand when declaring hand in the deal function
global variables are evil. i would take more object oriented approach, like this
var Hand = function(bjcallback) {
this.cards = [];
this.onblackjack = bjcallback;
this.deck = [1,2,3,4,5,6,7,8,9,10,"Jack","Queen","King","Ace"];
this.values = {
"Jack": 10,
"Queen": 10,
"King": 10,
"Ace": 11
};
this.sum = function() {
var i, x, res = 0;
for (i in this.cards) {
x = this.cards[i];
if (typeof(x) != 'number') { x = this.values[x] };
res += x;
};
return res
};
this.pick = function() {
var pos = Math.floor(Math.random() * this.deck.length);
var card = this.deck[pos];
console.log(card);
return card
};
this.deal = function(n) {
n = n || 2;
for (var i=0; i<n; i++) this.cards.push(this.pick())
};
this.hit = function() {
this.cards.push(this.pick());
if (this.sum() > 21) this.onblackjack();
}
}
var hurray = function() { alert('Blackjack!') };
var hand = new Hand(hurray);
hand.deal();
hand.hit();
note that i'm not much into cards so i might have confused terminology or counting
Related
I'm developing a little game of nothing at all more commonly called "Pathfinding"; and I am crashing on a small error that I have never encountered (I am young dev);
I have searched everywhere but I do not understand why this error appears.
I am experiencing this error:
Uncaught TypeError: current.distance is not a function
at search_min_distance (pathfinding.js:127)
at game (pathfinding.js:151)
at HTMLDocument. (pathfinding.js:173)
document.addEventListener("DOMContentLoaded", function() {
const NBR_POINT = 10;
const MIN_SPACING = 100;
const HEIGHT = window.innerHeight;
const WIDTH = window.innerWidth;
class point {
constructor(x, y, name, id) {
this.x = x;
this.y = y;
this.part = document.createElement("div");
this.part.className = name;
this.part.id = id;
}
distance(cmp) {
return Math.sqrt(Math.pow(cmp.x - this.x, 2) + Math.pow(cmp.y - this.y, 2));
}
}
function random(mode) {
if (!mode)
return Math.random() * ((WIDTH - 100) - 100) + 100;
else
return Math.random() * ((HEIGHT - 100) - 100) + 100;
}
function printPoint(stk, crt) {
var block = 0;
do {
block = 0;
var x = random(0);
var y = random(1);
if (stk.length != 0) {
for (let i = 0; i < stk.length; i++) {
if (x < (stk[i].x + MIN_SPACING) && x > (stk[i].x - MIN_SPACING) && y < (stk[i].y + MIN_SPACING) && y > (stk[i].y - MIN_SPACING)) {
block = 1;
break;
}
}
}
} while (block == 1);
var ids = stk.length + 1;
if (crt == "current")
var p = new point(x, y, "point courant", ids);
else
var p = new point(x, y, "point", ids);
p.part.style.bottom = p.y + "px";
p.part.style.left = p.x + "px";
document.body.appendChild(p.part);
return p;
}
function polyPoint() {
var stk = new Array();
for (let i = 0; i < NBR_POINT - 1; i++) {
stk.push(printPoint(stk, null));
}
printPoint(stk, "current");
return stk;
}
function imp_session() {
var dark_status = sessionStorage.getItem('dark_mode');
if (dark_status == 1)
document.body.classList.add("darkmode");
if (dark_status == 0)
document.body.classList.remove("darkmode");
}
function srv_DarkMode() {
document.addEventListener("keypress", function(event) {
let keypress = event.key;
var dark_status = sessionStorage.getItem('dark_mode');
if (keypress == "d") {
if (dark_status == null) {
dark_status = 0;
sessionStorage.setItem('dark_mode', dark_status);
}
if (dark_status == 1) {
this.body.classList.remove("darkmode");
dark_status = 0;
//To be able to delete sessions and not add them afterwards and error duplicate key.
sessionStorage.removeItem('dark_mode');
sessionStorage.setItem('dark_mode', dark_status);
} else {
this.body.classList.add("darkmode");
dark_status = 1;
//To be able to delete sessions and not add them afterwards and error duplicate key.
sessionStorage.removeItem('dark_mode');
sessionStorage.setItem('dark_mode', dark_status);
}
}
});
}
function search_min_distance(stk, current) {
let min = current.distance(stk[0]);
let tmp;
let real = min;
for (let i = 1; i < stk.length; i++) {
if (stk[i].id = current.id)
continue;
tmp = current.distance(stk[i]);
if (tmp < min)
real = i;
}
return real;
}
function game(stk) {
var cp = document.getElementsByClassName('courant');
cp[0].addEventListener("click", function(event) {
alert("txt");
});
var distId = search_min_distance(stk, cp[0]);
var p = document.getElementsByClassName('point');
for (let i = 0; i < p.length; i++) {
if (p[i].id != cp[0].id || p[i].id != distId) {
p[i].addEventListener("click", function(event) {
alert("txt");
});
}
}
}
function init() {
imp_session();
srv_DarkMode();
return polyPoint();
}
game(init());
});
-> current and stk [0] are indeed of "type" point.
All the remaining code does not seem important to me, but if necessary I will provide it.
I thank you in advance ! Be indulgent...
The point you are getting using the getElement function just returns
the js object, it does not contain any functions from the class.
You need to create a new class instance from this obtained point as follows inside the search_min_distance function
const { x, y, name, id } = current;
const currentPoint = new Point(x, y, name, id);
let min = currentPoint.distance(stk[0]);
I suggest you write a util function to calculate the distance between two points, passing the two points as arguments. It will be a cleaner approach.
Bind distance function to this inside constructor
class point {
constructor(x, y, name, id) {
this.x = x;
this.y = y;
this.part = document.createElement("div");
this.part.className = name;
this.part.id = id;
// bind distance method
this.distance = this.distance.bind(this);
}
distance(cmp) {
return Math.sqrt(Math.pow(cmp.x - this.x, 2) + Math.pow(cmp.y - this.y, 2));
}
}
The name of error is "TypeError". And That's not just for fun. Possible problems in search_min_distance:
stk is not defined or its length is 0
stk is not array of points (typeof point[])
point is not defined or it's not point (typeof point)
Sure problems:
point.id is not defined, it's only in point.part
if (stk[i].id = current.id)
to
if (stk[i].part.id = current.part.id)
Your code is only errors.
Finally all this for a simple mistake of inattention; I took dom for my array and put an assignment where there should have been an equal .. thanks everyone.
if (stk[i].id = current.id)
as
if (stk[i].id == current.id)
and
var distId = search_min_distance(stk, cp[0]);
as
var distId = search_min_distance(stk, stk[cp[0].id]);
My game is an idle one where you click protons, neutrons, and electrons and when you have enough of some, you can build hydrogen and so forth. I kind of got my local variables to work but now I am having issues with the buying stage.
Basically hydrogen costs 1 proton and one electron, when you click on the button, it runs the function SetHydrogen(), when it does that, it is supposed to run based off of the variable HydrogenCost. I am not sure if any of this is feasible.
var protons = Number(localStorage.setItem("ProtonS", Pcount));
var neutrons = Number(localStorage.NeutronS);
var electrons = Number(localStorage.ElectronS);
var hydrogens = Number(localStorage.HydrogenS);
function SaveVariables(){
if (localStorage.getItem("ProtonS")){
localStorage.setItem("ProtonS", Pcount);
protons = Number(localStorage.ProtonS);
} else {
localStorage.ProtonS = Number(localStorage.ProtonS);
}
if (localStorage.NeutronS){
localStorage.NeutronS = neutrons;
neutrons = Number(localStorage.NeutronS);
} else {
neutrons = Number(localStorage.NeutronS);
}
if (localStorage.ElectronS){
localStorage.ElectronS = electrons;
electrons = Number(localStorage.ElectronS);
} else {
electrons = Number(localStorage.ElectronS);
}
if (localStorage.HydrogenS){
localStorage.HydrogenS = document.getElementByID("HydrogenTotal").innerHTML;
hydrogens = Number(localStorage.HydrogenS);
} else {
hydrogens = 0;
}
}
function LoadVariables(){
buying = 0;
CanUBuy = false;
protons = Number(localStorage.ProtonS);
neutrons = Number(localStorage.NeutronS);
electrons = Number(localStorage.ElectronS);
hydrogens = Number(localStorage.HydrogenS);
}
function update(){
protonTap.onmousedown = function() {protons = protons + 1};
neutronTap.onmousedown = function() {neutrons = neutrons + 1};
electronTap.onmousedown = function() {electrons = electrons + 1};
};
function draw(){
ProtonsTotal.value = protons.toFixed(0);
NeutronsTotal.value = neutrons.toFixed(0);
ElectronsTotal.value = electrons.toFixed(0);
console.log(hydrogens);
console.log(CanUBuy);
console.log(Pcount);
};
var mainloop = function() {update(), draw(), SaveVariables()};
var buying = 0;
function SetHydrogen(){
buying = 1;
HydrogenCost.buy;
if (CanUBuy = true){
HydrogenTotal.value ++;
buying = 0;
CanUBuy = false;
} else {
buying = 0;
}
}
function reset(){
CanUBuy = false;
protons = 0;
neutrons = 0;
electrons = 0;
hydrogens = 0;
buying = 0;
}
setInterval(mainloop, 16);
var CanUBuy = false;
var HydrogenCost = new buy(1,0,1);
function buy(ProtonCost, NeutronCost, ElectronCost){
if (buying = 1){
this.pCost = ProtonCost;
this.nCost = NeutronCost;
this.eCost = ElectronCost;
if (protons >= ProtonCost && neutrons >= NeutronCost && electrons >= ElectronCost) {
CanUBuy = true;
protons = protons - this.pCost;
neutrons = neutrons - this.nCost;
electrons = electrons - this.eCost;
} else{
CanUBuy = false;
alert("You don't have enough money");
}
} else if (buying = 0) {
buying = 0;
}
}
if(!localStorage.getItem('start')){
localStorage.setItem('start', Date.now());
}
var start = parseInt(localStorage.getItem('start'));
setInterval(function(){
ffs.value = ~~((Date.now() - start)/1e3);
}, 1e3);
At first, i think you should rethink your overall structure. You could shorten your code and make it reusable through OOP:
function stored(name,startvalue){
this.name=name;
this.value=+localStorage.getItem(name) || startvalue || 0;
}
stored.prototype={
change:function(by){
this.value+=by;
localStorage.setItem(this.name,this.value);
},
set:function(to){
this.value=to;
localStorage.setItem(this.name,this.value);
},
valueOf:function(){ return this.value;},
};
So you can do:
var neutrons=new stored("neutrons");
alert(+neutrons);//0, 5 on reload
neutrons.set(5);
alert(+neutrons);//5
Note the + to convert the stored object to its value.
A hydrogen function could look like this:
var protons=new stored("protons",10);
var electrons=new stored("electrons",10);
var hydrogens=new stored("hydrogens");
hydrogens.buy=function(){
if(+protons && +neutrons){
protons.change(-1);
neutrons.change(-1);
this.change(1);
}else{
alert("impossible. Sorry :(");
}
}
hydrogens.buy();//test
http://jsbin.com/pozinotida/1/edit?js
I'm going through Codecademy's lesson on building a Blackjack game with Javascript.
I'm having trouble coming up with code to put in the for-loop. I'm supposed to write a "score" method in the Hand constructor. It should loop over all of the cards in the Hand, summing up the result of the "getValue" call to each and return that sum.
Can someone help me out please? Thank You.
Here's my attempt, the relevant code is inside the for-loop at the bottom:
// Card Constructor
function Card(s, n) {
var suit = s;
var number = n;
this.getSuit = function() {
return suit;
};
this.getNumber = function() {
return number;
};
this.getValue = function() {
if (number >= 10) {
return 10;
} else if (number === 1) {
return 11;
} else {
return number;
}
};
};
//deal function
var deal = function() {
var randNum = Math.floor(Math.random() * 13) + 1;
var randSuit = Math.floor(Math.random() * 4) + 1;
console.log(randNum, randSuit);
return new Card(randSuit, randNum);
};
function Hand() {
var handArray = [];
handArray[0] = deal();
handArray[1] = deal();
this.getHand = function() {
return handArray;
};
this.score = function() {
var sum;
for (var i = 0; i < handArray; i++) {
sum += handArray[i].getValue;
return sum;
}
};
};
Well something like this should work :
this.score = function() {
return handArray.reduce( function( memo, val){
return memo + val.getValue();
});
};
I think you need to return the score, outside of the loop, like so:
this.score = function() {
var sum;
for (var i = 0; i < handArray; i++) {
sum += handArray[i].getValue();
}
return sum;
};
This fixed it. Thanks for your help!
this.score = function(){
var sum =0;
for(var i =0; i<handArray.length; i++){
sum += handArray[i].getValue();
};
return sum;
};
Please note: This is not a question about scope, per se. I understand that in order to make the code work, I should make a deep copy of the variable board rather than assigning var tboard = board. However, I am not clear why making a shallow copy has the effect I describe below.
I am experiencing something I find baffling. Basically, a global variable (board) gets altered and I have no clue how. board is initialized in the function NewGame() (which is called from select()) as an empty array. After it is initialized, nothing else is called until the user clicks a square on the board (assuming the user has selected Xs for simplicity). When that happens, the function playerMove() is called. The baffling thing is that console.log(board) at the top of playerMove() prints out an array that has an x is the clicked position and os everywhere else (ie not empty). This is bizarre because the board is empty at the end of select() (which called NewGame()) and nothing else should happen in between. To demonstrate this, I print out the function name at the top of each function and I print out the board variable in the select() function and playerMove() function to show that it changes despite nothing else being called. Please note that to get this behavior, refresh the page (otherwise the board variable starts out full of os). I think this must be somewhat an issue of scope (because I am not making a deep copy of board) but it's strange because I have no clue what is being called that is changing the variable before it gets printed out at the top of playerMove().
Here is the link to my pen and the code: http://codepen.io/joshlevy89/pen/MKjxop?editors=101
$(document).ready(function() {
var pSym; // player's symbol
var cSym; // computer's symbol
var board;
var whosMove; // can be "player" or "computer" or "neither"
var gameOver;
setup();
$("#newgame").on('click', '#X', select);
$("#newgame").on('click', '#O', select);
$("#restart").on('click', setup);
$("table").on('click', 'td', playerMove);
function playerMove()
{
console.log('playerMove');
console.log(board);
if (whosMove === "player")
{
var val = $(this).data('value');
$('#g' + val).text(pSym);
var arr = PositionToCoords(val);
board[arr[0]][arr[1]] = pSym;
var tboard = board;
var gc = gameCheck(tboard);
if (gc>=0)
{
endGame(gc);
setTimeout(function(){setup();}, 1000);
return;
}
whosMove = "computer";
computerMove();
}
}
function computerMove() {
console.log('computerMove');
//var p1 = Math.floor(Math.random() * 3);
//var p2 = Math.floor(Math.random() * 3);
var tboard = board;
var pos = chooseMove(tboard);
var arr = PositionToCoords(pos);
board[arr[0]][arr[1]] = cSym;
DrawPosition(arr[0], arr[1], cSym);
var tboard = board;
var gc = gameCheck(tboard);
if (gc>=0) {
endGame(gc);
setTimeout(function(){setup();}, 1000);
return;
}
whosMove = "player";
}
function chooseMove(inboard) {
console.log('chooseMove');
// get the possible moves
var moves=[];
var scores = [];
for (var i=1;i<10;i++) {
var arr = PositionToCoords(i);
if (inboard[arr[0]][arr[1]] === undefined) {
moves.push(i);
var tboard = inboard;
tboard[arr[0]][arr[1]] = cSym;
var gc = gameCheck(tboard);
scores.push(gc);
}
}
//console.log(moves);
//console.log(scores);
return moves[0]; // TEMPORARY
}
function endGame(gc) {
console.log('endGame');
var str;
if (gc===1) { // somebody won
if (whosMove==="player"){
str = "You Won!"
}
else {
str = "You Lost :(";
}
}
else if (gc === 0){//draw
str = "It's a draw."
}
html = '<div id="closer">' + str + '</div>';
$('#endgame').html(html);
}
function gameCheck(tboard) {
console.log('gameCheck');
// get symbol to check for
var sym;
if (whosMove === "player") {
sym = pSym;
} else {
sym = cSym;
}
// check if in a row
var hrow;
var vrow;
// check for horizonal row
for (var i = 0; i < 3; i++) {
hrow = true;
vrow = true;
for (var j = 0; j < 3; j++) {
if (tboard[i][j] !== sym) {
hrow = false;
}
if (tboard[j][i] !== sym) {
vrow = false;
}
}
if ((hrow) || (vrow)) {
return 1;
}
}
var fdrow = true;
var bdrow = true;
for (var i = 0; i < 3; i++) {
if (tboard[i][i] !== sym) {
fdrow = false;
}
if (tboard[i][2 - i] !== sym) {
bdrow = false;
}
}
if ((fdrow) || (bdrow)) {
return 1;
}
// otherwise, check if board is full
var full = true;
for (var i = 1; i < 10; i++) {
var arr = PositionToCoords(i);
if (tboard[arr[0]][arr[1]] === undefined) {
full = false;
break;
}
}
if (full === true) {
return 0;
}
// if neither 0 (tie) or win (1), return -1 (game not over)
return -1;
}
function select() {
console.log('select');
pSym = $(this).data('value');
$('#newgame').html('');
NewGame();
console.log(board);
}
function setup() {
console.log('select');
$('#endgame').html('');
html = '<div id="opener">Xs or Os? <div id="buttons">';
html += '<div id="X" data-value="X" class="btn btn-default">Xs</div>';
html += '<div id="O" data-value="O" class="btn btn-default">Os</div>';
html += '</div></div>';
$('#newgame').html(html);
}
function NewGame() {
console.log('NewGame');
$('td').empty();
board = new Array(3);
for (i = 0; i < 3; i++) {
board[i] = new Array(3)
};
if (pSym === "X") {
cSym = "O";
whosMove = "player";
} else {
cSym = "X";
whosMove = "computer";
computerMove();
}
}
function DrawPosition(p1, p2, sym) {
console.log('DrawPosition');
var pos = p1 * 3 + (p2 + 1);
$("#g" + pos).text(sym)
}
function PositionToCoords(pos) {
console.log('PositionToCoords');
var p1 = Math.ceil(pos / 3) - 1;
var p2 = ((pos - 1) % 3);
var arr = [p1, p2];
return arr;
}
});
Thanks in advance.
Simply add the break in the for loop fixes the problem. Am I missing anything?
function chooseMove(inboard) {
console.log('chooseMove');
// get the possible moves
var moves = [];
var scores = [];
for (var i = 1; i < 10; i++) {
var arr = PositionToCoords(i);
if (inboard[arr[0]][arr[1]] === undefined) {
moves.push(i);
var tboard = inboard;
tboard[arr[0]][arr[1]] = cSym;
var gc = gameCheck(tboard);
scores.push(gc);
break; // <<<<<<<<<<<< This break guarantees that the computer only makes one move
}
}
//console.log(moves);
//console.log(scores);
return moves[0]; // TEMPORARY
}
I meet a trouble with a function. actually I need to make this function to perform a calculation on some text fields. When I worked on a single line no problems. But recently, someone asked to make a table with multiple lines (one line can be added dynamically) so, I do the following function so that it can not only duplicate line but id change all the fields concerned, so I add class to these fields. therefore I proceed as follows:
function clone(line) {
newLine = line.cloneNode(true);
line.parentNode.appendChild(newLine);
var tab = document.getElementsByClassName('libelle_debours')
var i = -1;
while (tab[++i]) {
tab[i].setAttribute("id", "_" + i);
};
var cab = document.getElementsByClassName('ht_no_tva')
var j = -1;
while (cab[++j]) {
cab[j].setAttribute("id", "_" + j);
};
var dab = document.getElementsByClassName('ht_tva')
var k = -1;
while (dab[++k]) {
dab[k].setAttribute("id", "_" + k);
};
var eab = document.getElementsByClassName('taux')
var l = -1;
while (eab[++l]) {
eab[l].setAttribute("id", "_" + l);
};
var fab = document.getElementsByClassName('tva')
var m = -1;
while (fab[++m]) {
fab[m].setAttribute("id", "_" + m);
};
}
function delRow() {
var current = window.event.srcElement;
//here we will delete the line
while ((current = current.parentElement) && current.tagName != "TR");
current.parentElement.removeChild(current);
}
The problem in fact is the second function that is used to make the calculation:
function calcdebours() {
var taux = document.getElementById('debours_taux_tva').value;
var ht_no_tva = document.getElementById('debours_montant_ht_no_tva').value;
var ht_tva = document.getElementById('debours_montant_ht_tva').value;
var tva = Math.round((((ht_tva) * (taux)) / 100) * 100) / 100;;
if (taux == '') {
taux = 0;
}
if (ht_no_tva == '') {
ht_no_tva = 0;
}
if (ht_tva == '') {
ht_tva = 0;
}
document.getElementById('debours_montant_tva').value = tva;
document.getElementById('debours_montant_ttc').value = (tva) + parseFloat(ht_tva) + parseFloat(ht_no_tva)
}
function
montant_debours() {
var ttc = document.getElementById('debours_montant_ttc').value;
var ttc2 = document.getElementById('debours_montant_ttc2').value;
if (ttc == '') {
var ttc = 0;
} else {
var ttc = document.getElementById('debours_montant_ttc').value;
}
if (ttc2 == '') {
var ttc2 = 0;
} else {
var ttc2 = document.getElementById('debours_montant_ttc2').value;
}
tx = parseFloat(ttc) + parseFloat(ttc2);
document.getElementById('ttc_cheque').value = Math.round(tx * 100) / 100;
}
As Id are not the same, do I have to create as many functions
there are lines?
Is it possible to fit a single function to process each line?
If so can you tell me how?
If I'm not mistaken you can use for loop and append increment to the end of element's id. Like this:
trs = document.getElementById('container Id').getElementsByTagName('tr');
For (var i = 1, i <= trs.length; i++)
{
var el = document.getElementById('debours_montant_ttc' + i);
}