// Name: 
// Student ID: 
// Email: 

#include "mathable.h"
#include <iostream>
#include <iomanip>
#include <cassert>    // for assert()
#include <algorithm>  // for fill() 
/* You may include more standard library headers here if you see fit. */

using namespace std;

/* You may define extra functions anywhere in this file if you see fit. */


// Shuffle the tokens using the Fisher-Yates algorithm
void shuffleTokens(int* bag) {
    for (int i = T - 1; i > 0; i--) {
        int j = rand() % (i + 1); // random index from 0 to i
        swap(bag[i], bag[j]);
    }
}

// Fill up the bag with shuffled tokens based on official game's token listing
void fillBag(int* bag) {
#if JUNIOR == 1
    assert(T == 60 && "Token count differs from official one!");
    for (int i = 1, j = 0; i <= 20; i++) {
        for (int k = 0; k < (i > 10 ? 1 : 5); k++) {
            bag[j++] = i;
        }
    }
#else
    assert(T == 106 && "Token count differs from official one!");
    int tokens[] = {
        24, 25, 27, 28, 30, 32, 35, 36, 40, 42, 45, 48, 
        49, 50, 54, 56, 60, 63, 64, 70, 72, 80, 81, 90
    };
    bag[0] = 0;
    for (int i = 1; i <= 24; i++) {
        bag[i] = tokens[i - 1];
    }
    for (int i = 1, j = 1; i <= 21; i++) {
        for (int k = 0; k < (i > 10 ? 1 : 7); k++) {
            bag[24 + j++] = i;
        }
    }    
#endif
    shuffleTokens(bag);
}

// Return the number of tokens in the bag
int bagSize(int* bag) {
    int i = 0;
    for (; i < T; i++) {
        if (bag[i] == BLANK)
            break;
    }
    return i;
}

// Draw tokens from bag to fill up all empty slots in the specified rack
// as far as possible, and return the count of tokens drawn
int drawTokens(int* bag, int* rack) {
    int drawn = 0;
    for (int i = 0; i < R; i++) {
        // Draw a token from bag for each empty slot in rack
        if (rack[i] == BLANK) {
            for (int j = bagSize(bag) - 1; j >= 0; j--) {
                rack[i] = bag[j];
                bag[j] = BLANK;
                drawn++;
                break;
            }
        }
    }
    return drawn;
}

// Swap the token indexed by pos in rack with a random token in bag
void swapTokens(int* bag, int* rack, int pos) {
    int r = rand() % bagSize(bag); // random index from 0 to bag size - 1
    int temp;
    temp = bag[r];
    bag[r] = rack[pos];
    rack[pos] = temp;                                                                     // TODO: complete the code to realize the swap operation

    
}

// Print the content (tokens and empty slots) of the bag
// (to ease debugging if needed)
void printBag(int* bag) {
    const int LINE_WIDTH = 20;
    for (int i = 1; i <= T; i++) {
        cout << setw(2) << bag[i - 1] << " ";
        if (i % LINE_WIDTH == 0)
            cout << endl;
    }
    if (T % LINE_WIDTH != 0)
        cout << endl;
}

// Return the number of tokens on the rack
int rackSize(int* rack) {
    int size = 0;
    for (int i = 0; i < R; i++) {
        if (rack[i] != BLANK)
            size++;
    }
    return size;
}

// Print the tokens on the rack of a player
void printRack(int* rack) {
    cout << "[ ";
    for (int i = 0; i < R; i++) {
        if (rack[i] != BLANK)
            cout << rack[i] << ' ';
    }
    cout << ']' << endl;
}

// Return the position of token in rack if it exists and -1 otherwise 
int tokenInRack(int* rack, int token) {
    for (int i = 0; i < R; i++) {
        if (rack[i] != BLANK && rack[i] == token)
            return i;
    }
    return -1;
}

// Set up the game board with central tokens
void setupBoard(int board[][N]) {
    assert(N % 2 == 0 && "Board size must be even!");
    for (int i = 0; i < N; i++) {
        fill(board[i], board[i] + N, BLANK);
    }
    board[N/2 - 1][N/2 - 1] = 1;
    board[N/2 - 1][N/2] = 2;
    board[N/2][N/2 - 1] = 3;
    board[N/2][N/2] = 4;
}

// Print the game board
void printBoard(int board[][N]) {
    // Print column headers
    cout << "   ";
    for (int i = 0; i < N; i++)
        cout << setw(3) << char('A' + i);
    cout << endl;
    
    // Print row headings and cells
    for (int i = 0; i < N; i++) {
        cout << setw(2) << i + 1 << " |";
        for (int j = 0; j < N; j++) {
            if (board[i][j] == BLANK)
                cout << "__|";
            else
                cout << setw(2) << board[i][j] << '|';
        }
        cout << endl;
            
    }
}

// Return true if the cell at row y and column x is within the board dimensions,
// and false otherwise (i.e., outside the board)
bool isValidCell(int y, int x) {
    return 0 <= y && y < N && 0 <= x && x < N;
}

// Return true if putting the token on an empty cell at row y and column x can
// form a valid equation with the token being the result of adding, subtracting,
// multiplying or dividing two adjacent tokens next to it, be they to the right 
// or left, below or above the token, and false otherwise
bool isValidMove(int board[][N], int token, int y, int x, int& points) {
    // TODO; add a return statement in order to compile
    int check = 0;
    if (board[y][x] == BLANK && isValidCell(y, x)) {

        //check up
        if ((board[y][x - 1] + board[y][x - 2] == token) ||
            (board[y][x - 1] * board[y][x - 2] == token) ||
            (board[y][x - 1] / board[y][x - 2] == token) ||
            (board[y][x - 2] / board[y][x - 1] == token) ||
            (board[y][x - 1] - board[y][x - 2] == token) ||
            (board[y][x - 2] - board[y][x - 1] == token) && board[y][x - 1] != BLANK && board[y][x - 2] != BLANK) {

            points = points + token;
            check = 1;
        }

        //check down

        if ((board[y][x + 1] + board[y][x + 2] == token) ||
            (board[y][x + 1] * board[y][x + 2] == token) ||
            (board[y][x + 1] / board[y][x + 2] == token) ||
            (board[y][x + 2] / board[y][x + 1] == token) ||
            (board[y][x + 1] - board[y][x + 2] == token) ||
            (board[y][x + 2] - board[y][x + 1] == token) && board[y][x + 1] != BLANK && board[y][x + 2] != BLANK) {

            points = points + token;
            check = 1;
            }
        //check left

        if ((board[y - 1][x] + board[y - 2][x] == token) ||
            (board[y - 1][x] * board[y - 2][x] == token) ||
            (board[y - 1][x] - board[y - 2][x] == token) ||
            (board[y - 2][x] - board[y - 1][x] == token) ||
            (board[y - 1][x] / board[y - 2][x] == token) ||
            (board[y - 2][x] / board[y - 1][x] == token) && board[y - 1][x] != BLANK && board[y - 2][x] != BLANK) {

            points = points + token;
            check = 1;
        }

        //check left

        if ((board[y + 1][x] + board[y + 2][x] == token) ||
            (board[y + 1][x] * board[y + 2][x] == token) ||
            (board[y + 1][x] - board[y + 2][x] == token) ||
            (board[y + 2][x] - board[y + 1][x] == token) ||
            (board[y + 1][x] / board[y + 2][x] == token) ||
            (board[y + 2][x] / board[y + 1][x] == token) && board[y + 1][x] != BLANK && board[y + 2][x] != BLANK) {

            points = points + token;
            check = 1;
        }

        if (check == 1)
            return true;
        else
            return false;

    }
    else
        return false;
}

// Return true if at least one possible move can be found on the game board
// using the tokens on the specified rack and false otherwise
// (Note: It always returns false if the rack has no tokens left.)
bool possibleMoveExists(int board[][N], int* rack) {
    // TODO; add a return statement in order to compile
    for (int k = 0; k < R; k++){
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < 0; j++) {
                isValidMove(board, rack[k], i,j, points);
            }
        }
    }
        
}
modify the above bool possibleMoveExists(int board[][N], int* rack) function part