ruffle-rs / ruffle

A Flash Player emulator written in Rust
https://ruffle.rs
Other
15.59k stars 809 forks source link

The CPU is breaking the Gomoku rules in Wuzi Chess. #3118

Open Jmousy opened 3 years ago

Jmousy commented 3 years ago

Describe the bug wuzichess

When playing Wuzi Chess (same as Gomoku rules), on a CPU turn, the CPU stone is overlaid at the same location on the player's stone.

It was difficult to explain, so I attached a Gif that was slowed down. In the Ruffle version, you can see that the white stones are overlaid with black stones.

There is no such problem in the Original Version, and it happens very frequently in Ruffle. The problem can be easily reproduced by placing the stone diagonally along the line of the stone placed by the CPU.

WuziChess.zip

Expected behavior The game should proceed according to the normal Gomoku rules.

Is the problem with the Ruffle desktop app, extension, or self-hosted version? Probably happens on all platforms

What platform are you using?

ousia commented 3 years ago

Many thanks for your report, @jooy0224.

For some strange reason, Ruffle replaces white stones with black ones.

I’m afraid it’s not easy to detect why this value change happens.

CUB3D commented 3 years ago

The underlying cause here is that when the player places a stone the variable _root.table is updated with a 1 in the position where the stone was placed so the CPU knows which positions are taken. This happens in "DefineButton2 (19)/BUTTONCONDACTION:16" with the following code _root.table[ypos][xpos] = 1, in Flash Player xpos/ypos are correctly set, however in Ruffle they are set to undefined. Changing that line to _root.table[_root.ypos][_root.xpos] = 1 stops the CPU player from overwriting the players moves.

n0samu commented 1 year ago

Exactly the same problem occurs in another version of the game called Five Secret Stones: https://github.com/ruffle-rs/ruffle/files/9865345/five.zip

Toad06 commented 1 year ago

Seems like the code in DefineButton2 (19) doesn't operate in the right scope? For instance, if you add this:

testme = 123;
trace(_root.testme); // 123 in FP, undefined in Ruffle
trace(this); // empty string in FP, "_level0.b(int)" in Ruffle
trace(this.testme); // undefined in FP, 123 in Ruffle
trace(_level0.b123); // _level0.b123 in FP and Ruffle
n0samu commented 1 year ago

I feel like this might be related to #1029 somehow, what do you think?

Toad06 commented 1 year ago

In fact, this seems to be another instance of #3839 (again 😢) - the code I posted above gives different results depending on the position it is pasted in DefineButton2 (19):

trace(this); // "_level0.b(int)" in FP and Ruffle
removeMovieClip(_root.b add _root.num); // removeMovieClip issue is about to strike again!
trace(this); // empty string in FP, "_level0.b(int)" in Ruffle
(...)
_root.table[ypos][xpos] = 1; // xpos, ypos should now be read from "_root", not "_level0.b(int)"
n0samu commented 1 year ago

Alright, thanks for checking!

Jmousy commented 1 year ago

Hmm... I checked on the 2023-03-02 Nightly Selfhosted build, but I'm still having issues. 😭

The problem can easily be reproduced by placing stones diagonally to block the attack by the CPU. Tested with the SWF attached to the description above.

image

Toad06 commented 1 year ago

Thanks for testing. The issue I posted in my previous comment is only partially fixed: trace(this) now displays results that match Flash Player, but the xpos and ypos variables are not read from the right scope.

_root.xpos = (int(this._x + 0.5) - 15) / 20 - 1;
// (...)
trace(xpos); // undefined in FP and Ruffle
removeMovieClip(_root.b add _root.num);
trace(xpos); // a number in FP, undefined in Ruffle
// (...)
_root.table[ypos][xpos] = 1;
n0samu commented 1 year ago

Looks like the game somehow broke again between when I last tested it and when the PR was merged. Hopefully @CUB3D can take a look!

Toad06 commented 1 year ago
_root.xpos = (int(this._x + 0.5) - 15) / 20 - 1;
// (...)
trace(xpos); // undefined in FP
removeMovieClip(_root.b add _root.num);
trace(xpos); // a number in FP
// (...)
_root.table[ypos][xpos] = 1;

Looks like the game somehow broke again between when I last tested it and when the PR was merged.

This was indeed working with 6a5eb43274b58cdd55814a2621f94e14be951130. However, the behavior wasn't correct either as both of the trace(xpos) were returning a number (so the first xpos was no longer read from the right scope).

The game then breaks again in af9810c22edea7bef4fbcfdca5829238f921d486, and both of the trace(xpos) are now returning undefined (issue with the second xpos).

Lord-McSweeney commented 1 year ago

This debug assert is probably relevant to the scoping issue: thread 'main' panicked at 'Scope::set: No top-level movie clip scope', core/src/avm1/scope.rs:200:13

   2: ruffle_core::avm1::scope::Scope::set
             at ./core/src/avm1/scope.rs:200:13
   3: ruffle_core::avm1::scope::Scope::set
             at ./core/src/avm1/scope.rs:195:13
   4: ruffle_core::avm1::activation::Activation::set_variable
             at ./core/src/avm1/activation.rs:2780:9
   5: ruffle_core::avm1::activation::Activation::action_set_variable
             at ./core/src/avm1/activation.rs:1907:9
   6: ruffle_core::avm1::activation::Activation::do_action
             at ./core/src/avm1/activation.rs:533:40
   7: ruffle_core::avm1::activation::Activation::run_actions
             at ./core/src/avm1/activation.rs:424:26
   8: ruffle_core::avm1::runtime::Avm1::run_stack_frame_for_action
n0samu commented 1 year ago

@olux997 mentioned another version of the game with the same problem: https://github.com/ruffle-rs/ruffle/files/12271961/5.zip