use crate::graphemes::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> {
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 div_small(base: u16, numb1: &[u16], numb2: &[u16]) -> (u16, Vec<u16>) {
let mut numb1 = numb1.to_owned();
let numb2 = numb2.to_owned();
let mut res: u16 = 0;
while greater_than(&numb1, &numb2) || numb1 == numb2 {
numb1 = subtract(base, &numb1, &numb2);
res += 1
}
let rem = numb1;
(res, rem)
}
pub fn div(base: u16, numb1: &[u16], numb2: &[u16]) -> (Vec<u16>, Vec<u16>) {
let numb1 = numb1.to_owned();
let mut divident: Vec<u16> = Vec::new();
let divisor = numb2.to_owned();
let mut quotient: Vec<u16> = Vec::new();
for digit in numb1 {
divident.push(digit);
let (quo, rem) = div_small(base, ÷nt, &divisor);
quotient.push(quo);
divident = rem;
}
(trim_base_vec(&mut quotient), trim_base_vec(&mut divident))
}
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);
}
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> {
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
}