Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
50 views

JavaScript Games Autores

This document provides a tutorial for building a simple snake game using only HTML, JavaScript, and CSS. It discusses setting up the game board as a 2D array, creating div elements for each cell, and initializing the game state with properties for the snake's position, direction, and length. It begins implementing the game logic by defining functions to start the game with default values and reset the state. The next part will make the snake visible and add keyboard controls.

Uploaded by

Martin Morales
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
50 views

JavaScript Games Autores

This document provides a tutorial for building a simple snake game using only HTML, JavaScript, and CSS. It discusses setting up the game board as a 2D array, creating div elements for each cell, and initializing the game state with properties for the snake's position, direction, and length. It begins implementing the game logic by defining functions to start the game with default values and reset the state. The next part will make the snake visible and add keyboard controls.

Uploaded by

Martin Morales
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 24

JavaScript Games

A simple snake game in pure


HTML and JavaScript, part 1
Mar 31, 2018 • permalink • comment @hjnilsson

Many people who are starting out with a new project get caught up in deciding on
technologies, what frameworks to use and what database to pick. When often —
especially if you are a beginner — it is a better idea to just get started, and make
something with the tools you know.

This is the first part of a tutorial that will show how you can build a snake game in
less than a hundred lines of JavaScript, without any frameworks. There is some
HTML and CSS in addition, but nothing scary. Any beginner to the web platform
should be able to go through the guide, and experienced developers will learn
something new as well.

Getting started with Snake

Start with an empty HTML document and open it in Chrome. Insert the following
code that just sets up a HTML document with style / script tags and a function to
set up the game.

<!DOCTYPE html5>
<html>
<head>
<title>Snake in pure HTML/JavaScript/CSS</title>
<style>
html {
text-align: center;
font-family: Helvetica, Arial, Helvetica, sans-serif;
}
</style>
</head>
<body onload="initGame()">
<h1>Simple Snake</h1>
<div id="board"></div>

<script>
function initGame() {

}
</script>
</body>
</html>

View this in a new tab

Let’s start from the top: The head tag. In here we have a title to put a document
title on the page, as well as a style tag containing styling to center the contents of
the page horizontally and change the font to a sans-serif one.

The the body element, which contains a h1 element with the title of the game and
a single div element that will contain the game board. We have it tagged with the
id ‘board’ so we can access the element from JavaScript. We also have a script
that will soon contain all of our game logic.

The body element also has an onload handler, which calls the initGame
function defined in the script tag. This means that once the document is completely
loaded, the code inside initGame will run. There is nothing there yet, so lets’ get
started!

Note: If you view the source code on all examples, there will be a script tag at the bottom that
handles integration with the iframe when the examples are included on this page. You can inspect it
if you like, but it is not necessary to understand it.

Creating the board

We’ll start out by creating the game board.

The board will be represented as a two-dimensional array, that is, an array of


arrays. We create this as a constant variable inside the script tag called board , we
also define the width and height of the board with two constant variables. Here I
have arbitrarily picked 26 by 16 cells (this is a convenient size to fit on screen).

<script>
const board = [];
const boardWidth = 26, boardHeight = 16;

function initGame() {
// Logic to come
}
</script>

To make it simple, we’ll build the entire board out of div elements, and will style
these to look like cells, apples and the snake. We create these diivs by iterating
over the Y and X axes, creating columns and rows of items:

function initGame() {
for (var y = 0; y < boardHeight; ++y) {
for (var x = 0; x < boardWidth; ++x) {
var cell = {};
}
}
}

Each cell will be defined by an empty object {} . In this object we will put the state
for each cell.

We need to fetch the board from the DOM (remember the <div
id="board></div>" ?). We do this using document.getElementById and store
it in a variable. This is done outside the loops.

For every cell, we create a div element on the board via


document.createElement . Then we add this cell to the boardElement ,
meaning every cell will have a matching div in the DOM.

function initGame() {
const boardElement = document.getElementById('board');

for (var y = 0; y < boardHeight; ++y) {


for (var x = 0; x < boardWidth; ++x) {
var cell = {};

// Create a <div></div> and store it in the cell


object
cell.element = document.createElement('div');

// Add it to the board


boardElement.appendChild(cell.element);
}
}
}
You can use the developer tools for Chrome to look at the document structure, and
you will see all the elements.

There should be 26 * 16 = 416 div


elements in this list.

Finally, we need to store all these cells inside the board array of arrays. We do this
by creating an array for every row, and push ing the cells into this row in the inner
loop, and every row into the board array for every outer loop, giving us our final
initGame function:

function initGame() {
for (var y = 0; y < boardHeight; ++y) {
var row = [];
for (var x = 0; x < boardWidth; ++x) {
var cell = {};

// Create a <div></div> and store it in the cell


object
cell.element = document.createElement('div');

// Add it to the board


boardElement.appendChild(cell.element);

// Add to list of all


row.push(cell);
}

// Add this row to the board


board.push(row);
}
}
However, if you run this code, nothing will show up. This is because div elements
by default are invisible, we need to give the some styling to make them visible on
the page.

To make the divs visible, we assign them a black background color, a width and a
height. We do this using CSS, by adding some code inside the <style> tag in the
template. To style the cells we use the #board div selector. This targets all the
div elements inside the element with the id board .

If you try only this they will all lay out in a loooong column down the page that is 24
pixels wide. To fix this, we need to float the elements. This moves them around so
that there is not a line break after every element. Instead the page will now display
as rows and columns of solid blocks.

#board div {
background-color: black;
border: 1px solid grey;
box-sizing: border-box;
float: left;
width: 24px;
height: 24px;
}

View this in a new tab

The box-sizing property is necessary so that the width of the borders don’t
make the cells wider than 24px. You can read up on box-sizing if you are curious
about this.

If you view the above example, you will notice that the grid is not square,. We also
need to limit the board in width, so that the grid is only 26 cells wide. We specify
the width of #board to be 26 * 24px, and use the calc function in CSS to not
have to calculate this number manually. The margin: auto means that the board
will be centered horizontally on-screen.

#board {
width: calc(26 * 24px);
margin: auto;
}

We now have a black grid for the snake game!

View this in a new tab


It is not very interesting yet though, because we don’t have any snake on the game
board to control.

Keep track of the game state

Next we need to add the snake to the board. We start by defining the properties
the snake has in this game, there are a few:

 Direction — The snake is moving either left, right, up or down. We can store this as
strings 'Up' , 'Down' , 'Left' and ‘ Right ’.
 Position — Defined as a X and Y position on the board. Note that 0, 0 will be top left
on the board and 25, 15 will be bottom right.
 Length — Length of the snake in segments.

Let’s create global variables for these properties:

// Add this after the global <script> tag


var snakeX;
var snakeY;
var snakeDirection;
var snakeLength;

We also need to store the tail of the snake. To keep track of this, we store the
information about the tail in the board. So we’ll add a property snake to every cell
on the board.

We’ll give it an integer value of 0 to denote that the snake is not on the space (at
the start of the game).

// Update this inside the initGame function


var cell = {
snake: 0
};

Start the game


We also need to give some default values to the snake properties. We’ll do that in
a new startGame function. This function will set all the properties to default values
at the start of the game.

The snake will start moving upwards, with a length of 5 segments. It will start in the
center of the board (divide width and height by 2), we need to use Math.floor
here to round down, since if the board width is 25, 12.5 is not a meaningful position
on the grid.
function startGame() {
// Default position for the snake in the middle of the
board.
snakeX = Math.floor(boardWidth / 2);
snakeY = Math.floor(boardHeight / 2);
snakeLength = 5;
snakeDirection = 'Up';

// Set the center of the board to contain a snake


board[snakeY][snakeX].snake = 1;
}

Why create a new function for this? We could just use default values for global
variables? The reason is we also need to do the same thing when the player dies
to reset the game state, by putting it in a function we can reuse.

In other words: initGame will only run once for the entire application, but
startGame will run multiple times.

Add a call to startGame from the end initGame (before the final } ). With this
addition, we’re done with the first part of the tutorial.

View final result in new tab

Wrapping up
Next time, we will make the snake visible on the board and implement keyboard
controls, so that you can steer it around the board using the keyboard.

A simple snake game in pure


HTML and JavaScript, part 2
Apr 19, 2018 • permalink • comment @hjnilsson

You should first read part 1 of the tutorial.

This is the second part of our quest to make a simple Snake game in the browser.
In this part, we will code the game loop, rendering and controls for the game.
We left off with an empty game board in part 1, with the game state set up. Now it’s
time to start implementing the game logic. You can view the result from part 1 here,
right click → View Source to see the code.

The game loop


First thing we’ll do is to make the game loop. The game loop is a generic term for
the code that constantly runs in the background inside games. This way, games
are different from most other programs in that they require no input from the user to
do things. Think about it, most computer programs do not do anything unless you
click a key, move the mouse or tap a button. But games always do something,
even when the user is just looking at the screen. The code that runs constantly in
the background, is called the game loop.

To run the game loop; we will create a new function. We call it simply gameLoop .
This function will run repeatedly during the duration of the game. It will handle
rendering and moving the snake around the board.

function gameLoop() {
// This function calls itself, with a timeout of 1000
milliseconds
setTimeout(gameLoop, 1000);
}

The setTimeout call will the the function again, recursively, every second so that
any code inside will run repeatedly in the background.

We also need to start the loop by adding an initial call to gameLoop at the end of
the startGame function:

function startGame() {
// ... code from before
startGame();

// Start the game loop (it will call itself with


timeout)
gameLoop();
}

The next step is to iterate over the entire board and update the DOM (ie. the HTML
div elements we created in part 1) with a different CSS class if the corresponding
cell contains the snake. We do this by looping over the Y and X axes, and checking
if the board has a snake , if so, we set the element’s class to "snake" . Else we
remove any class set.
function gameLoop() {
// Loop over the entire board, and update every cell
for (var y = 0; y < boardHeight; ++y) {
for (var x = 0; x < boardWidth; ++x) {
var cell = board[y][x];

if (cell.snake) {
cell.element.className = 'snake';
}
else {
cell.element.className = '';
}
}
}

// This function calls itself, with a timeout of 1000


milliseconds
setTimeout(gameLoop, 1000);
}

We also need to style the snake class, so it looks like a snake (green). Add the
following inside the <style> tag to do that:

#board .snake {
background-color: green;
}

Now when we refresh the page, the center element on the board should be green.
It should look like the example below.

View this in a new tab

Now that the initial snake is visible, we need to make it to move around the board.

Moving the snake


To make the snake move, we need to extend the game loop.

Before we update the board, we should look at what direction the snake is heading.
Using the direction, we update the position of the snake (the snakeX and snakeY
global variables) accordingly. Then we also need to update the board (the
board[y][x].snake variable). When the board is updated, it will automatically
update div element with the snake class, because the code that does that will
follow immediately after our check.
So what does this look like in code? We have the snakeDirection global
variable to define the direction the snake is heading, right now it always has the
value "Up" , but we also need to check for "Left" , "Right" , "Down" . For each
direction, we change the value of either snakeX or snakeY by 1. Changing
snakeY will move the snake either up or down, changing snakeX will move the
snake left or right.

Remember that snakeX = 0 and snakeY = 0 is the upper left of the board. So to
make the snake move right, we increase snakeX . To make it go down, we
increase snakeY . And the reverse for left and up. In code, it looks like this:

// Update position depending on which direction the snake


is moving.
switch (snakeDirection) {
case 'Up': snakeY--; break;
case 'Down': snakeY++; break;
case 'Left': snakeX--; break;
case 'Right': snakeX++; break;
}

// Update the board at the new snake position


board[snakeY][snakeX].snake = 1;

After updating the snake position, we also update the board at the new position to
set the snake as present. This code should be inserted inside gameLoop before
the double for-loops.

When you run the code, this should be the result:

View this in a new tabMost likely this appears as a green line from the center and
up. Refresh the page to see the snake slowly move up.

As you can see, the snake moves up the board slowly, since the direction is always
"Up" , the next step will be to make it possible to change the direction of the snake.

Handling input
Next step is handling input. Input will be done using the keyboard (sorry, mobile
readers). To capture this we need to bind the onKeyDown event. We check what
key was pressed and update the snakeDirection accordingly.

We create a new function to do this, called enterKey

function enterKey(event) {
// Update direction depending on key hit
}

We also need to add the onkeydown event handler to the body element. Here we
already have one event handler to initializes the game, so add another one that
handles the key presses:

<body onload="initGame()" onkeydown="enterKey(event)">

Inside the function, we will use the another switch statement to check what key
was pressed — in this case we check for all the arrow keys — and update the
direction of the snake. This will then automatically get picked up by the game loop
and the we will be able to control the snake!

function enterKey(event) {
// Update direction depending on key hit
switch (event.key) {
case 'ArrowUp': snakeDirection = 'Up'; break;
case 'ArrowDown': snakeDirection = 'Down'; break;
case 'ArrowLeft': snakeDirection = 'Left'; break;
case 'ArrowRight': snakeDirection = 'Right'; break;
default: return;
}

// This prevents the arrow keys from scrolling the


window
event.preventDefault();
}

The call to preventDefault is necessary, so that pressing the arrow keys do not
perform their default action (that scrolls the page up/down/left/right).

Try the link below to try it out, note that if you collide with the walls, the game will
crash and you can’t play any more. If that happens, refresh to restart the game.

Try out controlling the snake in a new tab

The walls
Let’s fix that bug with the walls that makes the game crash, and we’ll have a
controllable snake game!

To check for the walls, we simply need to add an if statement inside the game
loop after updating the snake position. This will check if the new position is outside
the board by comparing against 0 (snake can’t be on a negative position) and
boardWidth / boardHeight .

If we detect that the snake is outside the board, we restart the game by calling
startGame , this will reset both the position, length and direction of the snake.

// Check for walls, and restart if we collide with any


if (snakeX < 0 || snakeY < 0 || snakeX >= boardWidth || snakeY
>= boardHeight) {
startGame()
}

// Update the board at the new snake position


board[snakeY][snakeX].snake = 1;

We also need to update startGame to clear the board from the snake, so the old
snake is not visible when the game restarts. Add the following for loop inside
startGame to do that:

// Clear the board


for (var y = 0; y < boardHeight; ++y) {
for (var x = 0; x < boardWidth; ++x) {
board[y][x].snake = 0;
}
}

Now we can play the game without it crashing. Try it out by clicking below and
playing using the arrow keys:

View this in a new tabClick the frame to focus. You can now steer the snake
around using the arrow keys. The game will reset if you collide with the walls.

However, the snake remains on the board as we move around. So we have one
thing left on the todo list.

Making the snake disappear


To remove the snake, we need to keep track of the tail.

We can use the board to store this information. So rather than trying to keep track
of where different snake segments are on the board. We store how many more
iterations of the game loops the Snake should be visible in every cell.

We then simply decrease this as we iterate over the board.


We need to make a few small changes to accommodate this. First, we need to
replace the assignments board[snakeY][snakeX].snake = 1; to assign the
snakeLength instead. So find the two places with that piece of code and replace
with: board[snakeY][snakeX].snake = snakeLength;

Now, instead of just storing if there is a snake on the board, we store the remaining
length of the snake on that cell.

The next part is changing the loop over the entire board. Instead of checking for
cell.snake , we want to check if the value is greater than zero. If so, there is a
snake on that cell, so we still set the snake class, but we also decrease the value
of cell.snake by 1.

The update code inside the game loop will look like this:

var cell = board[y][x];

if (cell.snake > 0) {
cell.element.className = 'snake';
cell.snake -= 1;
}
else {
cell.element.className = '';
}

Finally I also decreased the setTimeout call to 1000 / snakeLength . This


make the speed of the game dependent on the length of the snake. Try out the
result below:

View this in a new tabYou can now control the snake around using the arrow keys,
and it disappears as you move.

Now we have an almost playable version of the game. All that remains is collecting
those delicious apples (and not being able to move through yourself). We’ll write
this code in the next part.

A simple snake game in pure


HTML and JavaScript, part 3
Jun 10, 2018 • permalink • comment @hjnilsson
You should first read part 1 and part 2 of the tutorial.

It’s time to complete our small snake game (long timeout between posts due to
work). Last time we made the snake move on the board and added keyboard
controls. Now all that remains is picking up the apples and collision detection with
the tail.

Placing apples
First step is placing the apples on the board.

This is something we will do many times, so we introduce a new function


placeApple that handles this.

Apples should be assigned to a random position, so we pick a random cell on the


board, using the Math.random and Math.floor functions in combination to pick
an integer (non-decimal) number for the X and Y positions. We then update the
board at this position with the property apple set to the value 1 .

function placeApple() {
// A random coordinate for the apple
var appleX = Math.floor(Math.random() * boardWidth);
var appleY = Math.floor(Math.random() * boardHeight);

board[appleY][appleX].apple = 1;
}

Ta place an apple on the board when the game starts, update the startGame
function. Before the final } brace, insert a call to the placeApple() function.

We also need to update the loop in this function to clear all apples on the board.
The end of the startGame function will thus look like this, with a call to the new
function and an updated loop:

// Clear board
for (var y = 0; y < boardHeight; ++y) {
for (var x = 0; x < boardWidth; ++x) {
board[y][x].snake = 0;
board[y][x].apple = 0;
}
}

// Set the center of the board to contain a snake


board[snakeY][snakeX].snake = snakeLength;
// Place the first apple on the board.
placeApple();

We also need to check in the render loop for the apple value (the same place we
check the board for the snake value) and set a different CSS class if there is an
apple on that spot. In other words, we update the gameLoop function with the
following else if statement.

if (cell.snake > 0) {
cell.element.className = 'snake';
cell.snake -= 1;
}
else if (cell.apple === 1) {
cell.element.className = 'apple';
}
else {
cell.element.className = '';
}

And finally, add a matching CSS class, to style the apple red on the board:

#board .apple {
background-color: red;
}

Once these changes have been made, the red apple should appear on the board.
You can also look at the source of the below sample.

View this in a new tabThere should now be a red apple on the board, but we can't
collect it.

The final piece of the puzzle, will be to pick up the apples and tail collisions.

Collecting apples
To check if the snake collided with an apple, we will update the game loop with
another if statement. Add this after checking if we collided with any walls (as
before):

// Collect apples
if (board[snakeY][snakeX].apple === 1) {
snakeLength++;
board[snakeY][snakeX].apple = 0;
placeApple()
}

We check if an apple is present on the cell we are moving to, if that is the case we
increase the length of the snake, remove the apple and place a new apple on the
board. This makes the game playable:

View this in a new tabYou can now collect apples, and make the snake grow.

Collisions with the tail


If you play the game above long enough, you’ll notice you don’t die if you go
through your own tail. This is the final thing we need to add to our game.

This requires a very similar check to the one we had for apples, but we instead
check if the snake property is set. If it is, we just restart the game. The following if
statement goes before the one we added before to pick up apples:

// Tail collision
if (board[snakeY][snakeX].snake > 0) {
startGame();
}

Mission success
And there you have it, a complete snake game made entirely in simple HTML,
JavaScript and CSS. Try it out below:

View this in a new tabThe final game now works!

After revelling in your success, we can note there are still bugs to be fixed:

 Apples can be placed ontop of the snake, making them invisible! In


placeApple we should prevent this by always finding a free position on the
board.
 You can walk backwards and collide with yourself. We should check in
enterKey that we don’t reverse the direction of the snake.

After fixing the bugs, try to extend the game. Here are some ideas on what can be
done:

 Replace the snake and Apple with cooler graphics, try using background-
image .
 Golden apples that give three times the length extension, but disappear if you
don’t pick it up fast enough.
 A score display to show the user how many apples they picked up.
 Continuing on score, a high score table. And maybe store it in localStorage
so it persists?
 Only start the game after the user gives some input after dying.
 Mobile support is atrocious, try to make it playable on an iPhone!
 Maybe don’t using 1000 / snakeLength for timeout, as the game quickly
becomes impossible due to the speed. Try some other formula that is more
fair.

Checar .- ORTENSIA REYES TREJO

Verificar que la información verificada este correcta(dictamen)

Si candidato-> Casado pregunte el ingreso del Candidato y si este tiene ingreso<4500 el sistema
pregunte el ingreso de su esposo y se le sume y el importe de la suma debe de ser >= 5,500
E
gh the code is extensible enough that adding more shouldn’t be an issue.

Have fun!

 prefix
 infix
 postfix

Prefix / Scheme
+ *5 8 + 5 - 1 4

Results
Tick Input Output Rest Error

// known operators
var operators = {
'+': function(a, b) { return a + b; },
'-': function(a, b) { return a - b; },
'*': function(a, b) { return a * b; },
'/': function(a, b) { return a / b; },
};

// process at this level


// return the result of this level and what we didn't use
// return a null value if we fail at any point
function step(current) {
// directly return numbers
if (!isNaN(parseFloat(current[0]))) {
return {
value: parseFloat(current[0]),
rest: current.slice(1)
};
}

// otherwise, we're going to have to recur


else {
var f = operators[current[0]];
// recur for left, use that rest for right
var left = step(current.slice(1));
if (left.value == null) return {value: null, rest:
[]};
var right = step(left.rest);
if (right.value == null) return {value: null,
rest: []};

// return at my level
return {
value: f(left.value, right.value),
rest: right.rest
};
}
}
step(input);

Infix
4 + 2 *7 - 1 *5 +

Results
Tick Command Reducing Error

// known operators
var operators = {
'+': function(a, b) { return a + b; },
'-': function(a, b) { return a - b; },
'*': function(a, b) { return a * b; },
'/': function(a, b) { return a / b; },
};
var precedence = [
['*', '/'],
['+', '-']
]

// process until we are done


while (input.length > 1) {
// find the first operator at the lowest level
var reduceAt = 0;
var found = false;
for (var i = 0; i < precedence.length; i++) {
for (var j = 1; j < input.length - 1; j++) {
if ($.inArray(input[j], precedence[i]) >=
0) {
reduceAt = j;
found = true;
break;
}
}
if (found) break;
}

// if we didn't find one, bail


if (!found) return;

// otherwise, reduce that operator


var newInput = [];
var f = operators[input[reduceAt]];

for (var i = 0; i < reduceAt - 1; i++)


newInput.push(input[i]);

newInput.push("" + f(
parseFloat(input[reduceAt - 1]),
parseFloat(input[reduceAt + 1])
));

for (var i = reduceAt + 2; i < input.length; i++)


newInput.push(input[i]);

input = newInput;
}

Postfix / RPN
4 2 7 *+ 1 6 - 5 *

Results
Tick Command Stack Error

// known operators
var operators = {
'+': function(a, b) { return a + b; },
'-': function(a, b) { return a - b; },
'*': function(a, b) { return a * b; },
'/': function(a, b) { return a / b; },
};

// run through all commands in the input


var stack = [];
for (var i = 0; i < input.length; i++) {
var cmd = input[i];

// known operator
if (cmd in operators) {
// get the function
var f = operators[cmd];

// sanity check
if (stack.length < f.length) {
error = 'not enough arguments';
break;
}

// get the correct number of arguments


var args = [];
for (var j = 0; j < f.length; j++)
args.unshift(stack.shift());

// apply and push back onto the stack


// note: the first argument to apply is 'this'
stack.unshift(f.apply(undefined, args));
}

// anything else, push onto the stack as either a number


or string
else {
stack.unshift(isNaN(parseFloat(cmd)) ? cmd :
parseFloat(cmd));
}
}

Hopefully this helps give some insight into what I was talking about in yesterday’s post. I
have to admit, I’m actually starting to like Javascript. It’s a bit strange at times, but it does
have a nice functional flavor which is always fun.

If you’d like to download the entire source code, you can do so here: source code
// known operators
var operators = {
'+': function(a, b) { return a + b; },
'-': function(a, b) { return a - b; },
'*': function(a, b) { return a * b; },
'/': function(a, b) { return a / b; },
};
var precedence = [
['*', '/'],
['+', '-']
]
// evalute a list assuming prefix notation
function evalPrefix(input) {
// process at this level
// return the result of this level and what we didn't use
// return a null value if we fail at any point
function step(current) {
// directly return numbers
if (!isNaN(parseFloat(current[0]))) {
return {
value: parseFloat(current[0]),
rest: current.slice(1)
};
}
// otherwise, we're going to have to recur
else {
var f = operators[current[0]];
// recur for left, use that rest for right
var left = step(current.slice(1));
if (left.value == null) return {value: null, rest: []};
var right = step(left.rest);
if (right.value == null) return {value: null, rest: []};
// return at my level
return {
value: f(left.value, right.value),
rest: right.rest
};
}
}
return step(input).value;
}
// evaluate a list assuming infix notation
function evalInfix(input) {
// process until we are done
while (input.length > 1) {
// find the first operator at the lowest level
var reduceAt = 0;
var found = false;
for (var i = 0; i < precedence.length; i++) {
for (var j = 1; j < input.length - 1; j++) {
if ($.inArray(input[j], precedence[i]) >= 0) {
reduceAt = j;
found = true;
break;
}
}
if (found) break;
}
// if we didn't find one, bail
if (!found) return;
// otherwise, reduce that operator
var newInput = [];
var f = operators[input[reduceAt]];
for (var i = 0; i < reduceAt - 1; i++)
newInput.push(input[i]);
newInput.push("" + f(
parseFloat(input[reduceAt - 1]),
parseFloat(input[reduceAt + 1])
));
for (var i = reduceAt + 2; i < input.length; i++)
newInput.push(input[i]);
input = newInput;
}
return input;
}
// evaluate a list assuming postfix notation
function evalPostfix(intpu) {
// run through all commands in the input
var stack = [];
for (var i = 0; i < input.length; i++) {
var cmd = input[i];
// known operator
if (cmd in operators) {
// get the function
var f = operators[cmd];
// sanity check
if (stack.length < f.length) {
error = 'not enough arguments';
break;
}
// get the correct number of arguments
var args = [];
for (var j = 0; j < f.length; j++)
args.unshift(stack.shift());
// apply and push back onto the stack
// note: the first argument to apply is 'this'
stack.unshift(f.apply(undefined, args));
}
// anything else, push onto the stack as either a number or string
else {
stack.unshift(isNaN(parseFloat(cmd)) ? cmd : parseFloat(cmd));
}
}
return stack[0];
}

You might also like