Skip to content
This repository was archived by the owner on Nov 24, 2023. It is now read-only.
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions docs/nodes/GAMES/GAMES_MATRIX/SNAKE_GAME/SNAKE_GAME.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@

[//]: # (Custom component imports)

import DocString from '@site/src/components/DocString';
import PythonCode from '@site/src/components/PythonCode';
import AppDisplay from '@site/src/components/AppDisplay';
import SectionBreak from '@site/src/components/SectionBreak';
import AppendixSection from '@site/src/components/AppendixSection';

[//]: # (Docstring)

import DocstringSource from '!!raw-loader!./a1-[autogen]/docstring.txt';
import PythonSource from '!!raw-loader!./a1-[autogen]/python_code.txt';

<DocString>{DocstringSource}</DocString>
<PythonCode GLink='GAMES/GAMES_MATRIX/SNAKE_GAME/SNAKE_GAME.py'>{PythonSource}</PythonCode>

<SectionBreak />



[//]: # (Examples)

## Examples

import Example1 from './examples/EX1/example.md';
import App1 from '!!raw-loader!./examples/EX1/app.json';



<AppDisplay
nodeLabel='SNAKE_GAME'
appImg={''}
outputImg={''}
>
{App1}
</AppDisplay>

<Example1 />

<SectionBreak />



[//]: # (Appendix)

import Notes from './appendix/notes.md';
import Hardware from './appendix/hardware.md';
import Media from './appendix/media.md';

## Appendix

<AppendixSection index={0} folderPath='nodes/GAMES/GAMES_MATRIX/SNAKE_GAME/appendix/'><Notes /></AppendixSection>
<AppendixSection index={1} folderPath='nodes/GAMES/GAMES_MATRIX/SNAKE_GAME/appendix/'><Hardware /></AppendixSection>
<AppendixSection index={2} folderPath='nodes/GAMES/GAMES_MATRIX/SNAKE_GAME/appendix/'><Media /></AppendixSection>


Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
The SNAKE_GAME node is a specialized node that iterates through the body nodes for a given number of times.
To ensure proper functionality, the SNAKE_GAME node relies on a companion node called the `GOTO` node.
183 changes: 183 additions & 0 deletions docs/nodes/GAMES/GAMES_MATRIX/SNAKE_GAME/a1-[autogen]/python_code.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
import json
import random
from flojoy import flojoy, DataContainer
import numpy as np

from flojoy.small_memory import SmallMemory


memory_key = "snake_game_info"
snake_dimension = 22


class SnakeData:
def __init__(
self,
node_id,
x_coords=[int(snake_dimension / 2)],
y_coords=[int(snake_dimension / 2)],
delta_x=0,
delta_y=1,
is_finished=False,
food_x=int(snake_dimension / 2),
food_y=snake_dimension - 4,
to_grow=False,
) -> None:
self.node_id = node_id
self.x_coords = x_coords
self.y_coords = y_coords
self.delta_x = delta_x
self.delta_y = delta_y
self.is_finished = bool(is_finished)
self.food_x = food_x
self.food_y = food_y
self.to_grow = to_grow

def get_data(self):
return self.__dict__

@staticmethod
def from_data(node_id, data: dict):
if len(data) == 0:
return SnakeData(node_id)
snake_data = SnakeData(**data)
return snake_data

def print(self, prefix=""):
print(f"{prefix}snake Data:", json.dumps(self.get_data(), indent=2))


@flojoy
def SNAKE_GAME(dc_inputs: list[DataContainer], params: dict) -> dict:


# get snake game data
control_input = dc_inputs[0]

if control_input.type != "ordered_pair":
raise ValueError(
f"unsupported DataContainer type passed for SNAKE_GAME: {control_input.type}"
)

node_id = params.get(
"node_id", 0
) # WARNING: special case, it gets the node id from the params despite not being specified
print("NODE ID IS: ", node_id)
snake_data: SnakeData = load_data(node_id)

# get control inputs
delta_x = snake_data.delta_x
delta_y = snake_data.delta_y
if control_input.y[8]:
delta_x += -1
delta_y = 0
elif control_input.y[9]:
delta_x += 1
delta_y = 0
elif control_input.y[6]:
delta_y += -1
delta_x = 0
elif control_input.y[7]:
delta_y += 1
delta_x = 0

if delta_x + delta_y != 0:
snake_data.delta_x = int(delta_x / (abs(delta_x)) if delta_x != 0 else 0)
snake_data.delta_y = int(delta_y / (abs(delta_y)) if delta_y != 0 else 0)

# update snake position
snake_data.x_coords.insert(0, snake_data.x_coords[0] + snake_data.delta_x)
snake_data.y_coords.insert(0, snake_data.y_coords[0] + snake_data.delta_y)
if not snake_data.to_grow:
snake_data.x_coords.pop()
snake_data.y_coords.pop()
else:
snake_data.to_grow = False

# check if out of bounds
if (
snake_data.x_coords[0] < 0
or snake_data.x_coords[0] > snake_dimension - 1
or snake_data.y_coords[0] < 0
or snake_data.y_coords[0] > snake_dimension - 1
):
snake_data.is_finished = True

# check if snake is eating itself
for i in range(len(snake_data.x_coords)):
if i == 0:
continue
if (
snake_data.x_coords[0] == snake_data.x_coords[i]
and snake_data.y_coords[0] == snake_data.y_coords[i]
):
snake_data.is_finished = True

if snake_data.is_finished:
print("GAME OVER, RESETTING")
snake_data = SnakeData(node_id)
store_data(node_id, snake_data)
return output_game(snake_data)

# check if snake is eating food
if (
snake_data.x_coords[0] == snake_data.food_x
and snake_data.y_coords[0] == snake_data.food_y
):
snake_data.to_grow = True
next_x, next_y = get_next_food_spot(snake_data)
snake_data.food_x = next_x
snake_data.food_y = next_y

# store snake game data
store_data(node_id, snake_data)

# output game
return output_game(snake_data)


def load_data(node_id) -> SnakeData:
data = SmallMemory().read_memory(node_id, memory_key) or {}
print("LOAD DATA IS ", data)
snake_data = SnakeData.from_data(node_id=node_id, data=data)
return snake_data


def store_data(node_id, snake_data: SnakeData):
SmallMemory().write_to_memory(node_id, memory_key, snake_data.get_data())
snake_data.print("store snake game data")


def get_next_food_spot(snake_data):
taken = set()
for i in range(len(snake_data.x_coords)):
taken.add((snake_data.x_coords[i], snake_data.y_coords[i]))

free = set()
for i in range(snake_dimension):
for j in range(snake_dimension):
if (i, j) not in taken:
free.add((i, j))

return random.choice(list(free))


# def delete_data(node_id):
# SmallMemory().delete_object(node_id, memory_key)
# print("delete snake game data")


def output_game(snake_data):
r = [[10 for i in range(snake_dimension)] for j in range(snake_dimension)]
g = [[10 for i in range(snake_dimension)] for j in range(snake_dimension)]
b = [[10 for i in range(snake_dimension)] for j in range(snake_dimension)]
for i in range(len(snake_data.x_coords)):
x_coord = snake_data.x_coords[i]
y_coord = snake_data.y_coords[i]
g[y_coord][x_coord] = 255
r[snake_data.food_y][snake_data.food_x] = 255
dc = DataContainer(
type="image", r=np.array(r), g=np.array(g), b=np.array(b), a=None
)
print("OUTPUT GAME IS ", dc)
return dc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This node does not require any peripheral hardware to operate. Please see INSTRUMENTS for nodes that interact with the physical world through connected hardware.
1 change: 1 addition & 0 deletions docs/nodes/GAMES/GAMES_MATRIX/SNAKE_GAME/appendix/media.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
No supporting screenshots, photos, or videos have been added to the media.md file for this node.
1 change: 1 addition & 0 deletions docs/nodes/GAMES/GAMES_MATRIX/SNAKE_GAME/appendix/notes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
No theory or technical notes have been contributed for this node yet.
57 changes: 57 additions & 0 deletions docs/nodes/INSTRUMENTS/CONTROLLER/GAMEPAD/GAMEPAD.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@

[//]: # (Custom component imports)

import DocString from '@site/src/components/DocString';
import PythonCode from '@site/src/components/PythonCode';
import AppDisplay from '@site/src/components/AppDisplay';
import SectionBreak from '@site/src/components/SectionBreak';
import AppendixSection from '@site/src/components/AppendixSection';

[//]: # (Docstring)

import DocstringSource from '!!raw-loader!./a1-[autogen]/docstring.txt';
import PythonSource from '!!raw-loader!./a1-[autogen]/python_code.txt';

<DocString>{DocstringSource}</DocString>
<PythonCode GLink='INSTRUMENTS/CONTROLLER/GAMEPAD/GAMEPAD.py'>{PythonSource}</PythonCode>

<SectionBreak />



[//]: # (Examples)

## Examples

import Example1 from './examples/EX1/example.md';
import App1 from '!!raw-loader!./examples/EX1/app.json';



<AppDisplay
nodeLabel='GAMEPAD'
appImg={''}
outputImg={''}
>
{App1}
</AppDisplay>

<Example1 />

<SectionBreak />



[//]: # (Appendix)

import Notes from './appendix/notes.md';
import Hardware from './appendix/hardware.md';
import Media from './appendix/media.md';

## Appendix

<AppendixSection index={0} folderPath='nodes/INSTRUMENTS/CONTROLLER/GAMEPAD/appendix/'><Notes /></AppendixSection>
<AppendixSection index={1} folderPath='nodes/INSTRUMENTS/CONTROLLER/GAMEPAD/appendix/'><Hardware /></AppendixSection>
<AppendixSection index={2} folderPath='nodes/INSTRUMENTS/CONTROLLER/GAMEPAD/appendix/'><Media /></AppendixSection>


Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

The GAMEPAD node reads the input from a gamepad and returns a DataContainer with the following structure:
- it is of type ordered pair
- the x value indicates how many buttons are available
- the y value is a numpy array of booleans indicating which buttons are pressed
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
from typing import Optional
import hid
import numpy as np
from flojoy import OrderedPair, flojoy, DataContainer


@flojoy
def GAMEPAD(default: Optional[OrderedPair], params: dict) -> DataContainer:


gamepad_device = None
clicked_buttons = [False] * 12

for device in hid.enumerate():
if "gamepad" in device["product_string"].lower():
gamepad_device = device

if gamepad_device is None:
print("ERROR: No gamepad found")
return OrderedPair(x=np.array([]), y=np.array(clicked_buttons))

gamepad = hid.device()
gamepad.open(gamepad_device["vendor_id"], gamepad_device["product_id"])

report = gamepad.read(64)


check backside buttons

if report[6] & 1:
clicked_buttons[0] = True
if report[6] & 2:
clicked_buttons[1] = True


check rightside buttons

if report[5] & 0b01000000:
clicked_buttons[2] = True

if report[5] & 0b00100000:
clicked_buttons[3] = True

if report[5] & 0b10000000:
clicked_buttons[4] = True

if report[5] & 0b00010000:
clicked_buttons[5] = True


check leftside buttons

if report[4] & 0b10000000:
clicked_buttons[6] = True

if report[4] == 0b00000000:
clicked_buttons[7] = True

if report[3] & 0b10000000:
clicked_buttons[8] = True

if report[3] == 0b00000000:
clicked_buttons[9] = True


check center buttons

if report[6] & 0b00010000:
clicked_buttons[10] = True

if report[6] & 0b00100000:
clicked_buttons[11] = True

return OrderedPair(x=np.array([11]), y=np.array(clicked_buttons))
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This node does not require any peripheral hardware to operate. Please see INSTRUMENTS for nodes that interact with the physical world through connected hardware.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
No supporting screenshots, photos, or videos have been added to the media.md file for this node.
Loading