Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

snekjs

Package Overview
Dependencies
Maintainers
1
Versions
8
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

snekjs - npm Package Compare versions

Comparing version 0.1.3 to 1.0.0

index.js

6

package.json
{
"name": "snekjs",
"version": "0.1.3",
"description": "no step on snek",
"version": "1.0.0",
"description": "A terminal-based Snake implementation written in JavaScript (Node.js) 🐍",
"author": {

@@ -12,3 +12,3 @@ "name": "Tania Rascia",

"scripts": {
"play": "node src/play.js"
"play": "node play.js"
},

@@ -15,0 +15,0 @@ "dependencies": {

@@ -1,5 +0,7 @@

# 🐍 no step on snek [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) [![snekjs on NPM](https://img.shields.io/npm/v/snekjs.svg?color=green&label=snekjs)](https://www.npmjs.com/package/snekjs)
# 🐍 Snek.js [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) [![snekjs on NPM](https://img.shields.io/npm/v/snekjs.svg?color=green&label=snekjs)](https://www.npmjs.com/package/snekjs)
Snake written in JavaScript for the terminal (Node.js).
A terminal-based Snake implementation written in JavaScript (Node.js).
![snek.gif](snek.gif)
## Instructions

@@ -10,3 +12,3 @@

```bash
git clone git@github.com:taniarascia/snek
git clone https://github.com/taniarascia/snek
cd snek

@@ -18,3 +20,3 @@ yarn && yarn play

Install the snek package:
Add the `snekjs` module.

@@ -25,42 +27,14 @@ ```bash

Create `play.js`
Create the game.
```js
// play.js
// index.js
const blessed = require('blessed')
const screen = blessed.screen({ smartCSR: true })
const { Interface, Game } = require('snekjs')
const ui = new Interface(screen, blessed)
const { UserInterface, Game } = require('snekjs')
const ui = new UserInterface(blessed, blessed.screen())
const game = new Game(ui)
function tick() {
if (game.gameOver()) {
// Show game over screen on collision and end game
ui.gameOverScreen()
ui.render()
return
}
ui.clearScreen()
ui.clearDirection()
game.renderDot()
game.moveSnake()
game.renderSnake()
ui.render()
}
// Iterate every 50ms
function main() {
setInterval(tick, 50)
}
// Generate the coordinates of the first dot before the game begins
game.generateDot()
// Begin game
main()
game.start()
```

@@ -71,5 +45,11 @@

```bash
node play.js
node index.js
```
## Acknowledgements
- [Vanya Sergeev](https://sergeev.io) for pointing out my snake collision bug, for advising me to make a single, reusable draw method, for showing me how to properly bind methods between classes, and for overall guidance and inspiration
- [Devin McIntyre](https://www.dev-eloper.com/) for general advice
- Panayiotis Nicolaou's [JavaScript Snake for Web](https://medium.freecodecamp.org/think-like-a-programmer-how-to-build-snake-using-only-javascript-html-and-css-7b1479c3339e) for initial logic
## Author

@@ -76,0 +56,0 @@

@@ -0,9 +1,32 @@

const { performance, PerformanceObserver } = require('perf_hooks')
/**
* @class Game
*
* Track the state of the snake, dot, and score
* The Game class tracks the state of three things:
*
* 1. The snake, including its direction, velocity, and location
* 2. The dot
* 3. The score
*
* The i/o of the game is handled by a separate UserInterface class, which is
* responsible for * detecting all event handlers (key press), creating the
* screen, and drawing elements to the screen.
*/
class Game {
constructor(ui) {
// The snake is an array of x/y coordinates
// User interface class for all i/o operations
this.ui = ui
this.reset()
// Bind handlers to UI so we can detect input change from the Game class
this.ui.bindHandlers(
this.changeDirection.bind(this),
this.quit.bind(this),
this.start.bind(this)
)
}
reset() {
// Set up initial state
this.snake = [

@@ -17,43 +40,59 @@ { x: 5, y: 0 },

]
this.dot = {}
this.score = 0
this.ui = ui // i/o
this.vx = 0 // horizontal velocity
this.vy = 0 // vertical velocity
this.dot = {} // the first random dot will be generated before the game begins
}
moveSnake() {
const goingUp = this.vy === -1
const goingDown = this.vy === 1
const goingLeft = this.vx === -1
const goingRight = this.vx === 1
if (this.ui.changingDirection) {
return
this.currentDirection = 'right'
this.directions = {
up: { x: 0, y: -1 },
down: { x: 0, y: 1 },
right: { x: 1, y: 0 },
left: { x: -1, y: 0 },
}
this.changingDirection = false
this.timer = null
this.ui.changingDirection = true
// Generate the first dot before the game begins
this.generateDot()
this.ui.resetScore()
this.ui.render()
}
if (this.ui.currentDirection === 'up' && !goingDown) {
this.vy = -1
this.vx = 0
/**
* Support WASD and arrow key controls. Update the direction of the snake, and
* do not allow reversal.
*/
changeDirection(_, key) {
if ((key.name === 'up' || key.name === 'w') && this.currentDirection !== 'down') {
this.currentDirection = 'up'
}
if (this.ui.currentDirection === 'down' && !goingUp) {
this.vy = 1
this.vx = 0
if ((key.name === 'down' || key.name === 's') && this.currentDirection !== 'up') {
this.currentDirection = 'down'
}
if ((key.name === 'left' || key.name === 'a') && this.currentDirection !== 'right') {
this.currentDirection = 'left'
}
if ((key.name === 'right' || key.name === 'd') && this.currentDirection !== 'left') {
this.currentDirection = 'right'
}
}
if (this.ui.currentDirection === 'right' && !goingLeft) {
this.vx = 1
this.vy = 0
/**
* Set the velocity of the snake based on the current direction. Create a new
* head by adding a new segment to the beginning of the snake array,
* increasing by one velocity. Remove one item from the end of the array to
* make the snake move, unless the snake collides with a dot - then increase
* the score and increase the length of the snake by one.
*
*/
moveSnake() {
if (this.changingDirection) {
return
}
this.changingDirection = true
if (this.ui.currentDirection === 'left' && !goingRight) {
this.vx = -1
this.vy = 0
// Move the head forward by one pixel based on velocity
const head = {
x: this.snake[0].x + this.directions[this.currentDirection].x,
y: this.snake[0].y + this.directions[this.currentDirection].y,
}
// Move the head forward by one pixel based on velocity
const head = { x: this.snake[0].x + this.vx, y: this.snake[0].y + this.vy }
this.snake.unshift(head)

@@ -64,3 +103,3 @@

this.score++
this.ui.setScore(this.score)
this.ui.updateScore(this.score)
this.generateDot()

@@ -73,9 +112,2 @@ } else {

renderSnake() {
// Render each snake segment as a pixel
this.snake.forEach((segment, i) => {
this.ui.drawSnake(segment, i)
})
}
generateRandomPixelCoords(min, max) {

@@ -89,3 +121,3 @@ // Get a random coordinate from 0 to max container height/width

this.dot.x = this.generateRandomPixelCoords(0, this.ui.gameContainer.width - 1)
this.dot.y = this.generateRandomPixelCoords(0, this.ui.gameContainer.height - 1)
this.dot.y = this.generateRandomPixelCoords(1, this.ui.gameContainer.height - 1)

@@ -100,29 +132,75 @@ // If the pixel is on a snake, regenerate the dot

renderDot() {
drawSnake() {
// Render each snake segment as a pixel
this.snake.forEach(segment => {
this.ui.draw(segment, 'green')
})
}
drawDot() {
// Render the dot as a pixel
this.ui.drawDot(this.dot)
this.ui.draw(this.dot, 'red')
}
gameOver() {
let collide = false
// If the snake collides with itself, end the game
this.snake.forEach((segment, i) => {
collide = segment.x === this.snake[0].x && segment.y === this.snake[0].y
})
const collide = this.snake
// Filter out the head
.filter((_, i) => i > 0)
// If head collides with any segment, collision
.some(segment => segment.x === this.snake[0].x && segment.y === this.snake[0].y)
return (
collide ||
// right wall
this.snake[0].x === this.ui.gameContainer.width - 1 ||
// left wall
this.snake[0].x === -1 ||
// top wall
this.snake[0].y === this.ui.gameContainer.height - 1 ||
// bottom wall
this.snake[0].y === -1
// Right wall
this.snake[0].x >= this.ui.gameContainer.width - 1 ||
// Left wall
this.snake[0].x <= -1 ||
// Top wall
this.snake[0].y >= this.ui.gameContainer.height - 1 ||
// Bottom wall
this.snake[0].y <= -1
)
}
showGameOverScreen() {
this.ui.gameOverScreen()
this.ui.render()
}
// Set to initial direction and clear the screen
clear() {
this.changingDirection = false
this.ui.clearScreen()
}
tick() {
if (this.gameOver()) {
this.showGameOverScreen()
clearInterval(this.timer)
this.timer = null
return
}
this.clear()
this.drawDot()
this.moveSnake()
this.drawSnake()
this.ui.render()
}
start() {
if (!this.timer) {
this.reset()
this.timer = setInterval(this.tick.bind(this), 50)
}
}
quit() {
process.exit(0)
}
}
module.exports = { Game }
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc