#include <cassert>
#include <algorithm>
#include <cctype>
#include <complex>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <ctime>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <limits>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <stack>
#include <sstream>
#include <tuple>
#include <typeinfo>
#include <unordered_set>
#include <unordered_map>
#include <vector>
using namespace std;

#define REP2(i, m, n) for(int i = (int)(m); i < (int)(n); i++)
#define REPD(i, n) for(int i = (int)(n) - 1; i >= 0; i--)
#define REP(i, n) REP2(i, 0, n)
#define ALL(c) (c).begin(), (c).end()
#define PB(e) push_back(e)
#define FOREACH(i, c) for(auto i = (c).begin(); i != (c).end(); ++i)
#define MP(a, b) make_pair(a, b)
#define BIT(n, m) (((n) >> (m)) & 1)

typedef long long ll;

template <typename S, typename T> ostream &operator<<(ostream &out, const pair<S, T> &p) {
  out << "(" << p.first << ", " << p.second << ")";
  return out;
}

template <typename T> ostream &operator<<(ostream &out, const vector<T> &v) {
  out << "[";
  REP(i, v.size()){
    if (i > 0) out << ", ";
    out << v[i];
  }
  out << "]";
  return out;
}

const ll MOD = 998244353;

ll modpow(ll n, ll p) {
  ll res = 1;
  while (p > 0) {
    if (p & 1) {
      res *= n;
      res %= MOD;
    }
    p >>= 1;
    n *= n;
    n %= MOD;
  }
  return res;
}

bool check(int a, int b, int c, unordered_map<int, unordered_map<int, int>> &color) {
  return !(color.count(a) && color[a].count(b) && color[a][b] != c);
}

int main(int argc, char *argv[])
{
  ll N, M;
  cin >> N >> M;
  vector<int> A(M), B(M), C(M);
  unordered_map<int, unordered_map<int, int>> color;

  bool conflict = false;
  REP(i, M) {
    cin >> A[i] >> B[i] >> C[i];
    color[A[i]][B[i]] = C[i];
    if (abs(A[i] - B[i]) >= 3 && color[B[i]].count(A[i]) &&
        ((color[A[i]][B[i]] + color[B[i]][A[i]]) % 2 == 1)) {
      conflict = true;
    }
  }

  if (conflict) {
    cout << 0 << endl;
    return 0;
  }
  set<pair<int, int>> fixed_far_pairs;
  REP(i, M) if (abs(A[i] - B[i]) >= 3 ) {
    fixed_far_pairs.insert(make_pair(min(A[i], B[i]), max(A[i], B[i])));
  }
  const ll prod = modpow(2, ((N - 2) * (N - 3) / 2) - fixed_far_pairs.size());

  ll dp[N][2];
  memset(dp, 0, sizeof(ll) * N * 2);
  REP(mask, 1 << 4) {
    if ((__builtin_popcount(mask)) % 2 != 0) {
      continue;
    }
    if (!check(2, 2, (mask >> 0) & 1, color) ||
        !check(1, 2, (mask >> 1) & 1, color) ||
        !check(2, 1, (mask >> 2) & 1, color) ||
        !check(1, 1, (mask >> 3) & 1, color)) {
      continue;
    }
    dp[1][mask & 1]++;
  }
  const int offset_x[5] = {1, 0, 1, -1, 1};
  const int offset_y[5] = {1, 1, 0, 1, -1};
  REP2(i, 2, N) REP(j, 2) REP(mask, 1 << 5) {
    if (__builtin_popcount(mask) % 2 != 0) {
      continue;
    }

    if ((__builtin_popcount(mask & 7) + j) % 2 != 0) {
      continue;
    }
    
    bool broken = false;
    REP(k, 5) {
      if (!check(i + offset_x[k], i + offset_y[k], (mask >> k) & 1, color)) {
        broken = true;
        break;
      }
    }
    if (!broken) {
      (dp[i][mask & 1] += dp[i - 1][j]) %= MOD;
    }
  }

  cout << prod * (dp[N - 1][0] + dp[N - 1][1]) % MOD << endl;
  return 0;
}


Measured memory_bytes: 13604