Created
June 11, 2010 19:24
-
-
Save grahamedgecombe/434920 to your computer and use it in GitHub Desktop.
Unique Candidate Identifier check digit calculator.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ============================================================================ | |
// Copyright (c) 2010-2011 Graham Edgecombe. All Rights Reserved. | |
// Unique Candidate Identifier Check Digit Calculator | |
// ============================================================================ | |
#include <stdlib.h> | |
#include <stdio.h> | |
#include <stdbool.h> | |
#define CENTRE_LEN 5 | |
#define BOARD_LEN 1 | |
#define YEAR_LEN 2 | |
#define CANDIDATE_LEN 4 | |
#define CHECK_LEN 1 | |
#define UCI_LEN (CENTRE_LEN + BOARD_LEN + YEAR_LEN + CANDIDATE_LEN + CHECK_LEN) | |
#define UCI_STR_LEN (UCI_LEN + 4) | |
#define PRODUCT 16 | |
#define DIVISOR 17 | |
struct uci | |
{ | |
char centre[CENTRE_LEN + 1]; | |
char board[BOARD_LEN + 1]; | |
char year[YEAR_LEN + 1]; | |
char candidate[CANDIDATE_LEN + 1]; | |
}; | |
char uci_char_to_num(char c, bool letters) | |
{ | |
if (c >= '0' && c <= '9') | |
return c - '0'; | |
else if (c >= 'A' && c <= 'I') | |
return c - 'A'; | |
else if (letters) | |
if (c == 'J' || c == 'Q' || c == 'X') | |
return 10; | |
else if (c == 'K' || c == 'R' || c == 'Y') | |
return 11; | |
else if (c == 'L' || c == 'S' || c == 'Z') | |
return 12; | |
else if (c == 'M' || c == 'T') | |
return 13; | |
else if (c == 'N' || c == 'U') | |
return 14; | |
else if (c == 'O' || c == 'V') | |
return 15; | |
else if (c == 'P' || c == 'W') | |
return 16; | |
return 0; | |
}; | |
char uci_check_digit(struct uci *u) | |
{ | |
unsigned char values[UCI_LEN - CHECK_LEN]; | |
int offset = 0; | |
for (int i = 0; i < CENTRE_LEN; i++) | |
values[offset++] = uci_char_to_num(u->centre[i], i < 2); | |
for (int i = 0; i < BOARD_LEN; i++) | |
values[offset++] = uci_char_to_num(u->board[i], true); | |
for (int i = 0; i < YEAR_LEN; i++) | |
values[offset++] = uci_char_to_num(u->year[i], false); | |
for (int i = 0; i < CANDIDATE_LEN; i++) | |
values[offset++] = uci_char_to_num(u->candidate[i], false); | |
unsigned int sum = 0; | |
for (int i = 0; i < (UCI_LEN - CHECK_LEN); i++) | |
sum += (PRODUCT - i) * values[i]; | |
int remainder = sum % DIVISOR; | |
if (remainder < 8) | |
return 'A' + remainder; | |
else if (remainder < 10) | |
return 'K' + remainder - 8; | |
else if (remainder == 11) | |
return 'R'; | |
else if (remainder == 12) | |
return 'T'; | |
else | |
return 'V' + remainder - 13; | |
} | |
void uci_str(char *str, struct uci *u) | |
{ | |
char check = uci_check_digit(u); | |
sprintf(str, "UCI%s%s%s%s%c", u->centre, u->board, u->year, u->candidate, check); | |
} | |
int main(int argc, char **argv) | |
{ | |
struct uci u; | |
sprintf(u.centre, "68199"); | |
sprintf(u.board, "0"); | |
sprintf(u.year, "01"); | |
sprintf(u.candidate, "2058"); | |
char str[UCI_STR_LEN]; | |
uci_str((char *) &str, &u); | |
printf("%s\n", str); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment