Skip to content

File logic.cpp

File List > COD_ENG_OUT_arduino_code > lib > Game_Logic > logic.cpp

Go to the documentation of this file

#include "logic.hpp"
#ifndef __AVR__
#include <cstdint>
#include <iostream>
#else
#include <Arduino.h>
#endif

namespace LOGIC {
cla_session::cla_session(uint8_t _u8_player_quantity,
                         uint8_t _u8_computer_quantity, mode _en_mode) {
  u8_player_quantity = _u8_player_quantity;
  u8_computer_quantity = _u8_computer_quantity;
  array_players[u8_player_quantity];
  u8_is_occupied_player_id = 10;
  u8_is_occupied_token_number = 10;

  for (int i = 0; i < _u8_player_quantity; i++) {
    if (_u8_player_quantity - _u8_computer_quantity > i)
      array_players[i] =
          new cla_manual_player(i, 5 + i * 10, _u8_computer_quantity,
                                this); // ID = i, Startposition = 5 + i * 10
    else {
      array_players[i] = new cla_computer_player(
          i, 5 + i * 10, _u8_computer_quantity, this,
          _en_mode); // ID = i, Startposition = 5 + i * 10
    }
  }
};

cla_player::cla_player(uint8_t _u8_player_id, uint8_t _u8_start_position,
                       uint8_t _u8_computer_quantity,
                       cla_session *_obj_my_session) {
  obj_my_session = _obj_my_session;
  u8_player_id = _u8_player_id;
  u8_start_position = _u8_start_position;
  for (int p = 0; p < 4; p++) {
    u8_token_position[p] =
        p + 1; // So each token has a unique position in the home field
  }
};

cla_computer_player::cla_computer_player(uint8_t _u8_player_id,
                                         uint8_t _u8_start_position,
                                         uint8_t _u8_computer_quantity,
                                         cla_session *_obj_my_session,
                                         mode _en_mode)
    : cla_player(_u8_player_id, _u8_start_position, _u8_computer_quantity,
                 _obj_my_session) {
  this->en_mode = _en_mode;
}

cla_manual_player::cla_manual_player(uint8_t _u8_player_id,
                                     uint8_t _u8_start_position,
                                     uint8_t _u8_computer_quantity,
                                     cla_session *_obj_my_session)
    : cla_player(_u8_player_id, _u8_start_position, _u8_computer_quantity,
                 _obj_my_session) {}

bool cla_session::Is_Occupied(uint8_t &_u8_is_occupied_player_id,
                              uint8_t &_u8_is_occupied_token_number,
                              uint8_t _u8_affected_track_position) {
  if (_u8_affected_track_position > 44) {
    _u8_is_occupied_player_id = 10;
    u8_is_occupied_token_number = 10;
    return false;
  } // In finish no token of a other player can be thrown
  for (uint8_t i = 0; i < u8_player_quantity; i++) {
    for (uint8_t a = 0; a < 4; a++) {
      if (array_players[i]->Get_Token_Position(a) ==
          _u8_affected_track_position) {
        _u8_is_occupied_player_id = i;
        _u8_is_occupied_token_number = a;
        return true; // i stands for the player ID, a for the token number
      }
    }
  }
  _u8_is_occupied_player_id = 10;
  u8_is_occupied_token_number = 10;
  return false; // 10 stands for no player/token at the given track position
}

bool cla_session::Return_Home(uint8_t _u8_affected_track_position) {
  if (Is_Occupied(u8_is_occupied_player_id, u8_is_occupied_token_number,
                  _u8_affected_track_position)) {
    array_players[u8_is_occupied_player_id]->Set_Token_Position(
        u8_is_occupied_token_number,
        u8_is_occupied_token_number +
            1); // Set_Token_Position sets the token
                // position to the home field (1,2,3,4)
    return true;
  } else {
    return false;
  }
};

uint8_t cla_player::Calculate_Possible_Position(uint8_t _u8_token_number,
                                                uint8_t _u8_dice_value) {
  uint8_t u8_token_progress = Get_Token_Progress(_u8_token_number);
  uint8_t u8_possible_absolute_position = 0;

  if ((u8_token_position[_u8_token_number] <= 4) &&
      (_u8_dice_value ==
       6)) { // token is in the home field and would move onto the track
    if (obj_my_session->Is_Occupied(obj_my_session->u8_is_occupied_player_id,
                                    obj_my_session->u8_is_occupied_token_number,
                                    u8_start_position) == true &&
        obj_my_session->u8_is_occupied_player_id == u8_player_id) {
      u8_possible_absolute_position =
          u8_token_position[_u8_token_number]; // token would throw itself
                                               // -> invalide move
    } else {
      u8_possible_absolute_position = u8_start_position;
    }
  } else if (u8_token_position[_u8_token_number] <= 4 &&
             _u8_dice_value != 6) { // token is in the home field and would
                                    // not move onto the track
    u8_possible_absolute_position = u8_token_position[_u8_token_number];
  } else if (u8_token_progress + _u8_dice_value > 39 &&
             u8_token_progress + _u8_dice_value <
                 44) { // token is on the track and would move into
                       // the finish and finish is not blocked by own
                       // token
    u8_possible_absolute_position = u8_token_progress + _u8_dice_value + 5;
  } else if (u8_token_progress + _u8_dice_value >
             43) { // token is on the track and would move out of the
                   // finish
    u8_possible_absolute_position = u8_token_position[_u8_token_number];
  } else if (u8_token_position[_u8_token_number] > 44 &&
             u8_token_position[_u8_token_number] + _u8_dice_value < 49) {
    // token is in the finish and would not move out of the finish and finish is
    // not blocked by own token
    u8_possible_absolute_position =
        u8_token_position[_u8_token_number] + _u8_dice_value;
  } else if (u8_token_position[_u8_token_number] > 44 &&
             u8_token_position[_u8_token_number] + _u8_dice_value > 49) {
    // token is in the finish and would move out of the finish
    u8_possible_absolute_position = u8_token_position[_u8_token_number];
  } else {
    uint8_t u8_possible_position =
        u8_token_position[_u8_token_number] + _u8_dice_value;
    if (u8_possible_position >
        44) { // token is on track and would move out of the track
      u8_possible_position = u8_possible_position - 40;
    }
    u8_possible_absolute_position = u8_possible_position;
  }
  for (int i = 0; i < 4; i++) {
    if (u8_possible_absolute_position == u8_token_position[i]) {
      return u8_token_position[_u8_token_number];
    }
  } // token would throw itself -> invalide move
  return u8_possible_absolute_position;
};

uint8_t cla_player::Move_Token(uint8_t _u8_token_number,
                               uint8_t _u8_dice_value) {
  uint8_t u8_possible_position =
      Calculate_Possible_Position(_u8_token_number, _u8_dice_value);
  bool bool_is_occupied = obj_my_session->Is_Occupied(
      obj_my_session->u8_is_occupied_player_id,
      obj_my_session->u8_is_occupied_token_number, u8_possible_position);
  if (u8_possible_position ==
      Get_Token_Position(
          _u8_token_number)) { // token stays on the same position (e.g would
                               // move out of the finish)
    return Get_Token_Position(_u8_token_number);
  } else if (bool_is_occupied == false) {
    // possible position is not occupied
    u8_token_position[_u8_token_number] = u8_possible_position;
    return u8_possible_position;
  } else if (bool_is_occupied == true &&
             obj_my_session->u8_is_occupied_player_id != u8_player_id &&
             u8_possible_position <= 44) {
    // possible position is occupied by another player -> other player gets
    // sent home
    obj_my_session->Return_Home(u8_possible_position);
    u8_token_position[_u8_token_number] = u8_possible_position;
    return u8_possible_position;
  } else {
    return 0; // Error
  }
};

int8_t cla_player::Is_Start_Field_Occupied_By_Own_Token() {
  uint8_t u8_counter = 0;
  for (uint8_t token = 0; token < 4; token++) {
    if (Get_Token_Position(token) <= 4) {
      u8_counter = u8_counter + 1;
    } else {
      u8_counter = u8_counter;
    }
  };
  if (obj_my_session->Is_Occupied(obj_my_session->u8_is_occupied_player_id,
                                  obj_my_session->u8_is_occupied_token_number,
                                  u8_start_position) &&
      u8_player_id == obj_my_session->u8_is_occupied_player_id &&
      u8_counter > 0) {
    return obj_my_session->u8_is_occupied_token_number;
  } else {
    return -1; // no own token at the start position
  }
};

uint8_t cla_player::Get_Token_Position(uint8_t _u8_token_number) {
  return u8_token_position[_u8_token_number];
};

uint8_t cla_player::Set_Token_Position(uint8_t _u8_token_number,
                                       uint8_t _u8_new_position) {
  u8_token_position[_u8_token_number] = _u8_new_position;
  return u8_token_position[_u8_token_number];
};

uint8_t cla_player::Get_Token_Progress(uint8_t _u8_token_number) {
  if (u8_token_position[_u8_token_number] >= 5) { // token is on the track
    int8_t i8_token_progress =
        u8_token_position[_u8_token_number] - u8_start_position;
    if (i8_token_progress < 0) { // to compensate the offset for each player
      i8_token_progress =
          u8_token_position[_u8_token_number] + 40 - u8_start_position;
    }
    if (u8_token_position[_u8_token_number] > 44) {
      i8_token_progress = u8_token_position[_u8_token_number] -
                          5; // to compensate the offset on the field
    }
    return i8_token_progress; // cannot be negative
  } else {
    return 0;
  }
};

status cla_player::Get_Player_Status() {
  uint8_t u8_status = 0; // Position < 5 -> start, 5<=Position<=44 -> Track,
                         // Position > 44 -> Finished
  for (int i = 0; i < 4; i++) {
    if (u8_token_position[i] <= 4) {
      u8_status += 0;
    } else if (u8_token_position[i] <= 44) {
      u8_status += 1;
    } else if (u8_token_position[i] > 44) {
      u8_status += 10;
    }
  };
  if (u8_status == 0) {
    return Start; // all tokens are in start
  } else if (u8_status > 0 &&
             u8_status <
                 4) { // at least one token is on the track, rest is in start
    return Start_Track;
  } else if (u8_status == 10 or u8_status == 20 or
             u8_status == 30) { // max 3 token are finished, rest in start
    return Start_Finished;
  } else if (u8_status > 10 && u8_status <= 12 or
             u8_status > 20 &&
                 u8_status <= 21) { // at least one is in start, one is
                                    // finished, rest on track
    return Start_Track_Finished;
  } else if (u8_status == 4) { // all tokens are on the track
    return Track;
  } else if (u8_status == 40) { // all tokens are finished
    return Finished;
  } else if (u8_status == 13 or u8_status == 22 or
             u8_status ==
                 31) { // at least one token is on track, rest is finished
    return Track_Finished;
  } else {
    return Error;
  }
};

uint8_t cla_player::Get_Player_Progress() {
  uint8_t u8_overall_progress = 0;
  for (uint8_t u8_token_number = 0; u8_token_number < 4; u8_token_number++) {
    u8_overall_progress +=
        this->cla_player::Get_Token_Progress(u8_token_number);
  }
  if (u8_overall_progress == 166) {
    return 28; // 166 means all tokens are in the finish
  }
  float f_scaled_progress =
      ((float)u8_overall_progress / 166.0f) * 27.0f + 1.0f;
  // To display the progress on LED-Matrix it nedds to be scaled to 1-28
  uint8_t u8_scaled_progress_rounded = (uint8_t)(f_scaled_progress + 0.5f);

  if (u8_scaled_progress_rounded > 27) {
    u8_scaled_progress_rounded = 27;
  } // 28 is the maximum progress and is only allowed to be reached when all
    // tokens are in the finish (166)

  return u8_scaled_progress_rounded;
};

int8_t cla_computer_player::Auto_Move(uint8_t _u8_dice_value,
                                      bool &_bool_occupied_flag,
                                      uint8_t &_u8_old_position) {
  int8_t i8_start_field_occupied_by_own_token =
      Is_Start_Field_Occupied_By_Own_Token();
  if (i8_start_field_occupied_by_own_token != -1) {
    _u8_old_position = Get_Token_Position(i8_start_field_occupied_by_own_token);
    _bool_occupied_flag = obj_my_session->Is_Occupied(
        obj_my_session->u8_is_occupied_player_id,
        obj_my_session->u8_is_occupied_token_number,
        Calculate_Possible_Position(i8_start_field_occupied_by_own_token,
                                    _u8_dice_value));
    Move_Token(i8_start_field_occupied_by_own_token, _u8_dice_value);
    // Computer must move away from start field if other tokens are in start
    return i8_start_field_occupied_by_own_token;
  } else if (_u8_dice_value == 6) {
    bool bool_home_occupied = false;
    for (int i = 0; i < 4; i++) {
      if (Get_Token_Position(i) <= 4) {
        bool_home_occupied = true;
      }
      if (bool_home_occupied) {
        _u8_old_position = Get_Token_Position(i);
        _bool_occupied_flag = obj_my_session->Is_Occupied(
            obj_my_session->u8_is_occupied_player_id,
            obj_my_session->u8_is_occupied_token_number, u8_start_position);
        Move_Token(i, _u8_dice_value);
        return i;
        // Computer must move a token out of the home field if at least one
        // token is in the home field
      }
    }
  }
  bool token_moved = false;
  switch (en_mode) {
  case Student:
    for (int n = 0; n < 4; n++) {
      uint8_t u8_possible_position =
          Calculate_Possible_Position(n, _u8_dice_value);
      // Check if a token can be moved (from token 0 to 3)
      if (u8_possible_position > 4 &&
          u8_possible_position != Get_Token_Position(n)) {
        // set occupied flag
        _bool_occupied_flag = obj_my_session->Is_Occupied(
            obj_my_session->u8_is_occupied_player_id,
            obj_my_session->u8_is_occupied_token_number, u8_possible_position);
        // set old position flag
        _u8_old_position = Get_Token_Position(n);
        Move_Token(n, _u8_dice_value);
        return n; // Token number that was moved
      }
    }
    return -1; // No token could be moved

  case Professor:
    for (int n = 0; n < 4; n++) {
      uint8_t u8_possible_position =
          Calculate_Possible_Position(n, _u8_dice_value);
      if (obj_my_session->Is_Occupied(
              obj_my_session->u8_is_occupied_player_id,
              obj_my_session->u8_is_occupied_token_number,
              u8_possible_position) == true &&
          obj_my_session->u8_is_occupied_player_id != u8_player_id &&
          u8_possible_position <= 44 && u8_possible_position > 4) {
        _u8_old_position = Get_Token_Position(n);
        Move_Token(n, _u8_dice_value);
        token_moved = true;
        _bool_occupied_flag = true;
        return n;
      }
    }
    // If no token could be moved -> student move (Fallback-Solution)
    if (token_moved == false) {
      for (int m = 0; m < 4; m++) {
        uint8_t u8_possible_position =
            Calculate_Possible_Position(m, _u8_dice_value);
        // Check if a token can be moved (from token 0 to 3)
        if (u8_possible_position > 4 &&
            u8_possible_position != Get_Token_Position(m)) {
          // set occupied flag
          _bool_occupied_flag = obj_my_session->Is_Occupied(
              obj_my_session->u8_is_occupied_player_id,
              obj_my_session->u8_is_occupied_token_number,
              u8_possible_position);
          // set old position flag
          _u8_old_position = Get_Token_Position(m);
          Move_Token(m, _u8_dice_value);
          return m;
        }
      }
    }
    return -1; // No token could be moved

  default:
    return -1; // Error
  }
}

uint8_t cla_session::Get_Player_Quantity() { return u8_player_quantity; };

uint8_t cla_session::Get_Computer_Quantity() { return u8_computer_quantity; };

uint8_t cla_player::Get_Start_Position() { return u8_start_position; };

int8_t cla_player::Auto_Move(uint8_t _u8_dice_value, bool &_bool_occupied_flag,
                             uint8_t &_u8_old_position) {
  return -1;
};

} // namespace LOGIC