Skip to content

Commit 860f046

Browse files
committed
init
0 parents  commit 860f046

13 files changed

+1308
-0
lines changed

.cargo/config.toml

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[build]
2+
target = "wasm32-unknown-unknown"
3+
4+
[target.wasm32-unknown-unknown]
5+
rustflags = [
6+
# Import memory from WASM-4
7+
"-C", "link-arg=--import-memory",
8+
"-C", "link-arg=--initial-memory=65536",
9+
"-C", "link-arg=--max-memory=65536",
10+
11+
# Temporary workaround for #255 issue.
12+
# Reserve 8192 bytes of Rust stack space, offset from 6560.
13+
# Bump this value, 16-byte aligned, if the framebuffer gets corrupted.
14+
"-C", "link-arg=-zstack-size=14752",
15+
]

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/target

Cargo.lock

+23
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
[package]
2+
name = "untangle"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7+
[lib]
8+
crate-type = ["cdylib"]
9+
10+
[dependencies]
11+
buddy-alloc = { version = "0.5.1", optional = true }
12+
fastrand = "2.1.1"
13+
14+
[profile.release]
15+
opt-level = "z"
16+
lto = true
17+
panic = "abort"
18+
strip = true
19+
codegen-units = 1
20+
21+
[features]
22+
# use `--no-default-features` or comment out next line to disable allocator
23+
default = ["buddy-alloc"]

README.md

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# untangle-rs
2+
3+
A game written in Rust for the [WASM-4](https://wasm4.org) fantasy console.
4+
5+
## How to play
6+
7+
You are presented with a collection of points on a plane, and some of these points are connected by straight lines. The challenge is to manipulate the positions of these points freely, with the ultimate objective of repositioning them in such a way that no line segment crosses another.
8+
9+
**Controls**: Select a point by tapping or clicking on it, then drag it to a new position.
10+
11+
## Building
12+
13+
Build the game by running:
14+
15+
```shell
16+
cargo build --release
17+
```
18+
19+
Then run it with:
20+
21+
```shell
22+
cd target/wasm32-unknown-unknown/release
23+
w4 run untangle.wasm
24+
```
25+
26+
You can optimize the binary file size using `wasm-opt` or `wasm-snip`, and then bundle it into an HTML file using the `w4 bundle` subcommand. Please ensure that you have the necessary tools installed and that your environment is properly set up to execute these commands.
27+
28+
```shell
29+
# In target/wasm32-unknown-unknown/release
30+
wasm-opt -Oz untangle.wasm -o untangle.wasm
31+
wasm-snip untangle.wasm -o untangle.wasm env::memory
32+
w4 bundle untangle.wasm --title "untangles" --html untangle.html
33+
```
34+
35+
For more info about setting up WASM-4, see the [quickstart guide](https://wasm4.org/docs/getting-started/setup?code-lang=rust#quickstart).
36+
37+
## Links
38+
39+
- [Documentation](https://wasm4.org/docs): Learn more about WASM-4.
40+
- [Snake Tutorial](https://wasm4.org/docs/tutorials/snake/goal): Learn how to build a complete game
41+
with a step-by-step tutorial.
42+
- [GitHub](https://github.com/aduros/wasm4): Submit an issue or PR. Contributions are welcome!

src/alloc.rs

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
use buddy_alloc::{BuddyAllocParam, FastAllocParam, NonThreadsafeAlloc};
2+
3+
// These values can be tuned
4+
const FAST_HEAP_SIZE: usize = 4 * 1024; // 4 KB
5+
const HEAP_SIZE: usize = 16 * 1024; // 16 KB
6+
const LEAF_SIZE: usize = 16;
7+
8+
static mut FAST_HEAP: [u8; FAST_HEAP_SIZE] = [0u8; FAST_HEAP_SIZE];
9+
static mut HEAP: [u8; HEAP_SIZE] = [0u8; HEAP_SIZE];
10+
11+
#[global_allocator]
12+
static ALLOC: NonThreadsafeAlloc = unsafe {
13+
let fast_param = FastAllocParam::new(FAST_HEAP.as_ptr(), FAST_HEAP_SIZE);
14+
let buddy_param = BuddyAllocParam::new(HEAP.as_ptr(), HEAP_SIZE, LEAF_SIZE);
15+
NonThreadsafeAlloc::new(fast_param, buddy_param)
16+
};

src/lib.rs

+136
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
#[cfg(feature = "buddy-alloc")]
2+
mod alloc;
3+
mod line;
4+
mod point;
5+
mod resource;
6+
mod scene;
7+
mod wasm4;
8+
9+
use line::{check_intersect, init_lines, Line, Lines};
10+
use point::{init_points, Point, Points, PointsSpeed};
11+
use scene::{update_finish, update_playing, update_title, update_end};
12+
use wasm4::{MOUSE_BUTTONS, MOUSE_LEFT};
13+
14+
use GameState::*;
15+
use MouseButtonState::*;
16+
use TitleState::*;
17+
18+
#[no_mangle]
19+
unsafe fn update() {
20+
let mouse = mouse_state();
21+
GAME.previous_mouse = *MOUSE_BUTTONS;
22+
GAME.seed += 1;
23+
match &GAME.state {
24+
Title(speed) => update_title(mouse, speed),
25+
Playing => update_playing(mouse),
26+
Finish(state) => update_finish(mouse, state),
27+
End => update_end(),
28+
}
29+
}
30+
31+
static mut GAME: Game = Game {
32+
points: Points::new(),
33+
lines: Lines::new(),
34+
previous_mouse: 0,
35+
holding_point: None,
36+
intersect_lines: None,
37+
state: Title(Screen(PointsSpeed::new())),
38+
seed: 0,
39+
difficulty: 6,
40+
metronome: 0,
41+
};
42+
43+
struct Game {
44+
points: Points,
45+
lines: Lines,
46+
previous_mouse: u8,
47+
holding_point: Option<usize>,
48+
intersect_lines: Option<(Line, Line)>,
49+
state: GameState,
50+
seed: u64,
51+
difficulty: u8,
52+
metronome: u32,
53+
}
54+
55+
unsafe fn init_game() {
56+
GAME.holding_point = None;
57+
GAME.previous_mouse = 0;
58+
loop {
59+
GAME.points = init_points(GAME.difficulty as usize, true);
60+
GAME.lines = init_lines(GAME.difficulty as usize);
61+
GAME.intersect_lines = get_intersect_lines();
62+
if GAME.intersect_lines.is_some() {
63+
break;
64+
}
65+
GAME.seed += 1;
66+
}
67+
}
68+
69+
fn mouse_state() -> MouseButtonState {
70+
let previous = unsafe { GAME.previous_mouse } & MOUSE_LEFT;
71+
let current = unsafe { *MOUSE_BUTTONS } & MOUSE_LEFT;
72+
match (previous == 1, current == 1) {
73+
(false, false) => Idle,
74+
(false, true) => Pressed,
75+
(true, false) => Released,
76+
(true, true) => Held,
77+
}
78+
}
79+
80+
#[inline]
81+
fn get_point(idx: usize) -> Point {
82+
unsafe { *unwrap(GAME.points.get(idx)) }
83+
}
84+
85+
fn get_intersect_lines() -> Option<(Line, Line)> {
86+
for l1 in unsafe { &GAME.lines } {
87+
for l2 in unsafe { &GAME.lines } {
88+
if l1.0 == l2.0 || l1.0 == l2.1 || l1.1 == l2.0 || l1.1 == l2.1 {
89+
continue;
90+
}
91+
if check_intersect(*l1, *l2) {
92+
return Some((*l1, *l2));
93+
}
94+
}
95+
}
96+
None
97+
}
98+
99+
enum MouseButtonState {
100+
Pressed,
101+
Held,
102+
Released,
103+
Idle,
104+
}
105+
106+
enum GameState {
107+
Title(TitleState),
108+
Playing,
109+
Finish(FinishState),
110+
End,
111+
}
112+
113+
enum TitleState {
114+
Screen(PointsSpeed),
115+
Start,
116+
}
117+
118+
enum FinishState {
119+
Twinkle(String),
120+
Win(String),
121+
Arrow(ArrowState),
122+
Curtain,
123+
}
124+
125+
enum ArrowState {
126+
Appear,
127+
WaitClick,
128+
}
129+
130+
#[inline]
131+
fn unwrap<T>(o: Option<T>) -> T {
132+
match o {
133+
Some(t) => t,
134+
None => std::process::abort(),
135+
}
136+
}

0 commit comments

Comments
 (0)