2

I am writing a c++ NodeJs native add-on using the v8 that implements a minimax tic-tac-toe AI.

I have a problem where nested functions are not working.

Here is my code:

namespace Game {
    Move bestMove(...) {
        // implementation
    }
}
namespace addon {
    using namespace v8;
    using std::vector;
    ...

    // this function returns the best move back to nodejs
    void bestMove(const FunctionCallbackInfo<Value>& args) {
        Isolate* isolate = args.GetIsolate();
        ...

        auto returnVal = Game::bestMove(params); // Game::bestMove() returns the best move for the computer

        args.GetReturnValue().Set((returnVal.row * 3) + returnVal.col); // returns the move back to nodejs
}

Normally, if the game board is this (computer is o):

    x _ _
    _ _ _
    _ _ _

The function shouldn't return 0 because it is already taken by x. However it seems to always return 0.

After I investigated a bit, I realized that the function Game::bestMove() never gets called.

Add yes, I know this is the problem because after I added std::cout << "Computing"; in the function Move bestMove(), it never got printed to the console.

However, if I add std::cout << "Computing"; in the function addon::bestMove(), it works.

There is also no compile time error thrown.

Thanks for any help.

Luke
  • 565
  • 5
  • 19

1 Answers1

2

This answer is only helpful if you're willing to move to using N-API via the C++ bindings, node-addon-api (available via npm). You're using C++ so it is probably the cleanest way to make the coding more straightforward and likely to work. Net, I can't tell you what is wrong with your code from what's posted, so if that's showstopper then no need to read on.

With node-addon-api your addon would look something like:

#include <napi.h>

// your move function
Napi::Value bestMove(const Napi::CallbackInfo& info) {
  Napi::Env env = info.Env();

  int move = Game::bestMove(params);

  // just return the number and the C++ inline wrappers handle
  // the details
  return Napi::Number::New(env, move);
}

// the module init function used in the NODE_API_MODULES macro below
Napi::Object Init(Napi::Env env, Napi::Object exports) {
  Napi::HandleScope scope(env);

  // expose the bestMove function on the exports object.
  exports.Set("bestMove", Napi::Function::New(env, bestMove));

  return exports;
}

NODE_API_MODULES(my_game, Init)

In JavaScript you'd just require the bindings file, typically in build/Release/my_game.node (or use the bindings package so you can just require('my_game')). So

const game = require('my_game')
...

move = game.bestMove()

I don't know enough details to flesh out the example any better.

I worked with Nan before the node-addon-api package and found it frustrating. I didn't try using V8 directly because it ties my application to a specific version of node.

If you're interested in more details check out https://github.com/nodejs/node-addon-api. It really quite well done.

Apologies if any of the code above has errors; I just made it up as I went.

bmacnaughton
  • 4,950
  • 3
  • 27
  • 36
  • Thanks for the fast reply! This really helped. – Luke Feb 09 '19 at 18:33
  • 1
    I get it. It's pretty hard to find definitive docs on this stuff and there aren't many people on stackoverflow that work in this area. It this works for you I'd appreciate it if you accepted the answer (you upvoted it). I only mention it because you're new to stackoverflow. – bmacnaughton Feb 09 '19 at 18:45