use crate::graphemes::grapheme_creation::GRAPHEMES;
pub fn vec_to_arr<T, const N: usize>(v: Vec<T>) -> [T; N] {
v.try_into()
.unwrap_or_else(|v: Vec<T>| panic!("Expected a Vec of length {} but it was {}", N, v.len()))
}
pub fn from_string(base: u16, number: &str) -> Vec<u16> {
if base > GRAPHEMES.len() as u16 {
panic!("There are not enough graphemes create number. Use a lower base");
}
let number = number.trim();
let digits: Vec<u16> = number
.split("")
.filter(|s| s != &"")
.map(|s| {
let byte_arr = s.as_bytes();
let mut byte_vec: Vec<u8> = Vec::new();
byte_vec.resize(4 - byte_arr.len(), 0);
for byte in byte_arr {
byte_vec.push(*byte);
}
let comp_arr = &vec_to_arr(byte_vec);
if let Some(key) =
GRAPHEMES
.iter()
.find_map(|(key, val)| if val == comp_arr { Some(key) } else { None })
{
if *key > base - 1 {
let error = String::from("value ")
+ number
+ " contains graphemes greater than number base "
+ &base.to_string();
panic!("{error}");
}
*key
} else {
let error = String::from("value ") + number + " not in valid graphemes";
panic!("{error}");
}
})
.collect();
digits
}
pub fn add(base: u16, numb1: &[u16], numb2: &[u16]) -> Vec<u16> {
let mut numb1 = numb1.to_owned();
numb1.reverse();
let mut numb2 = numb2.to_owned();
numb2.reverse();
let mut res: Vec<u16> = Vec::new();
let (greatest, smallest) = if numb1.len() > numb2.len() {
(&numb1, &numb2)
} else {
(&numb2, &numb1)
};
for i in 0..smallest.len() {
res.push(greatest[i] + smallest[i]);
}
for digit in greatest.iter().skip(smallest.len()) {
res.push(*digit);
}
for i in 0..res.len() {
if res[i] >= base {
if i == res.len() - 1 {
res.push(1);
} else {
res[i + 1] += 1;
}
res[i] -= base;
}
}
res.reverse();
res
}
pub fn subtract(base: u16, numb1: &[u16], numb2: &[u16]) -> Vec<u16> {
let mut numb1 = numb1.to_owned();
numb1.reverse();
let mut numb2 = numb2.to_owned();
numb2.reverse();
let mut res: Vec<i32> = Vec::new();
for i in 0..numb2.len() {
res.push(numb1[i] as i32 - numb2[i] as i32);
}
for digit in numb1.iter().skip(numb2.len()) {
res.push(*digit as i32);
}
for i in 0..res.len() {
if res[i] < 0 {
res[i + 1] -= 1;
res[i] += base as i32;
}
}
while res.last() == Some(&0_i32) {
res.pop();
}
res.reverse();
res.iter().map(|x| x.to_owned() as u16).collect()
}
pub fn trim_base_vec(vec: &mut Vec<u16>) -> Vec<u16> {
vec.reverse();
while vec.last() == Some(&0_u16) {
vec.pop();
}
vec.reverse();
vec.to_owned()
}
pub fn greater_than(numb1: &[u16], numb2: &[u16]) -> bool {
let numb1 = trim_base_vec(&mut numb1.to_owned());
let numb2 = trim_base_vec(&mut numb2.to_owned());
if numb1.len() > numb2.len() {
return true;
} else if numb1.len() == numb2.len() {
for i in 0..numb1.len() {
if numb1[i] > numb2[i] {
return true;
} else if numb2[i] > numb1[i] {
return false;
}
}
false
} else {
false
}
}
fn convert_base10(base: u16, numb: &[u16]) -> u128 {
let mut numb = numb.to_owned();
numb.reverse();
let mut res: u128 = 0;
for i in 0..numb.len() {
res += numb[i as usize] as u128 * (base as u128).pow(i as u32) as u128;
}
res
}
pub fn div(base: u16, numb1: &[u16], numb2: &[u16]) -> (Vec<u16>, Vec<u16>) {
let mut numb1 = numb1.to_owned();
let mut numb2 = numb2.to_owned();
trim_base_vec(&mut numb1);
trim_base_vec(&mut numb2);
if greater_than(&numb2, &numb1) {
return (vec![0], numb1);
}
let mut quo: Vec<u16> = Vec::new();
let mut divident: Vec<u16> = Vec::new();
for numb in &numb1 {
divident.push(*numb);
if greater_than(&numb2, ÷nt) {
quo.push(0);
} else {
let divident_base10 = convert_base10(base, ÷nt);
let divisor_base10 = convert_base10(base, &numb2);
let res = (divident_base10 / divisor_base10) as u16;
quo.push(res);
divident = subtract(base, ÷nt, &mul(base, &vec![res], &numb2));
}
}
let remainder = trim_base_vec(&mut subtract(base, &numb1, &mul(base, &quo, &numb2)));
(quo, remainder)
}
pub fn mul(base: u16, number1: &[u16], number2: &[u16]) -> Vec<u16> {
let numb1 = if greater_than(number1, number2) {
let mut numb1 = number1.to_owned();
numb1.reverse();
numb1
} else {
let mut numb2 = number2.to_owned();
numb2.reverse();
numb2
};
let numb2 = if !greater_than(number1, number2) {
let mut numb1 = number1.to_owned();
numb1.reverse();
numb1
} else {
let mut numb2 = number2.to_owned();
numb2.reverse();
numb2
};
let mut mul_pieces: Vec<Vec<u16>> = Vec::new();
for digit2 in numb2 {
let mut mul_piece: Vec<u16> = Vec::new();
let mut waiting_value: u16 = 0;
let mut placing_value: u16;
for digit1 in &numb1 {
let product = digit1 * digit2;
placing_value = waiting_value + (product - (product / base) * base);
waiting_value = product / base;
if placing_value >= base {
placing_value -= base;
waiting_value += 1;
}
mul_piece.push(placing_value);
}
if waiting_value != 0 {
mul_piece.push(waiting_value);
}
mul_piece.reverse();
mul_pieces.push(mul_piece);
}
for (i, piece) in mul_pieces.iter_mut().enumerate() {
for _ in 0..i {
piece.push(0);
}
}
let mut res: Vec<u16> = vec![];
for piece in mul_pieces {
res = add(base, &res, &piece);
}
trim_base_vec(&mut res)
}
fn as_base10(base: u16, mut numb: Vec<u16>) -> u16 {
let mut res: u128 = 0;
numb.reverse();
for (i, digit) in numb.iter().enumerate() {
res += *digit as u128 * (base as u128).pow(i as u32);
}
res as u16
}
fn from_base10(base: u16, mut numb: u16) -> Vec<u16> {
let mut res: Vec<u16> = Vec::new();
while numb > 0 {
res.push(numb % base);
numb /= base;
}
res.reverse();
res
}
pub fn convert(self_base: u16, self_digits: Vec<u16>, base: u16) -> Vec<u16> {
if base > GRAPHEMES.len() as u16 {
panic!("Cannot convert. Requested base is greater than number of graphemes.");
}
let mut base_as_self = from_base10(self_base, base);
let mut res: Vec<u16> = Vec::new();
let mut numb = self_digits;
while greater_than(&numb, &base_as_self)
|| trim_base_vec(&mut numb) == trim_base_vec(&mut base_as_self)
{
let (quotient, rem) = div(self_base, &numb, &base_as_self);
numb = quotient;
res.push(as_base10(self_base, rem));
}
res.push(as_base10(self_base, numb));
res.reverse();
res
}