Coding challenge optimization - c

I am participating in a coding challenge that consistes in the following:
We start with a number(size of the string) followed by a string (ex: 5WWFAE) by stdin.
The letters given represent elements, F-fire, W-water, E-earth, A-air. Fire and Water cancel each other and Earth and Air cancel as well.
The goal is to simplify the string by canceling the elements and print it, but you can only cancel adjacent members, for example: "7AFEAWWE" would result in "AWE".
In this challenge the points are given depending on how fast the program runs and how little memory you spend, somehow some people still have more points than me. Could you help-me optimising it?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define stack_is_empty() stack_index == -1
#define stack_push() stack[++stack_index] = c
#define stack_pop() --stack_index
#define can_join() (stack[stack_index] + c == 'F' + 'W') || (stack[stack_index] + c == 'A' + 'E')
void process_string(int len)
{
char c;
char *stack = malloc(len * sizeof(char));
register int stack_index = -1;
register int i = 0;
for (i = 0; i < len; ++i)
{
scanf("%c", &c);
if (stack_is_empty())
{
stack_push();
}
else if (can_join())
{
stack_pop();
}
else
{
stack_push();
}
}
printf("%*.*s\n", stack_index + 1, stack_index + 1, stack);
}
int main()
{
int len;
//* Input:
scanf("%d", &len);
if (len == 0)
{
printf("\n");
return 0;
}
process_string(len);
return 0;
}

Related

How to add periods in between letters in C Programming

I am new to C programming, and I am trying to figure out how to put a period in between letters. This is my code:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
void CreateAcronym(char userPhrase[], char userAcronym[]) {
int i;
int count = 0;
for (i = 0; i < strlen(userPhrase); ++i) {
if (i == 0 || userPhrase[i - 1] == ' ') {
if (isupper(userPhrase[i])) {
userAcronym[count++] = userPhrase[i];
}
}
}
userAcronym[count] = '\0';
}
int main() {
char userPhrase[1000];
char userAcronym[20];
fgets(userPhrase, 1000, stdin);
CreateAcronym(userPhrase, userAcronym);
printf("%s\n", userAcronym);
return 0;
}
Example Input: Institute of Electrical and Electronics Engineers
My current Output: IEEE
What the output should be: I.E.E.E.
How do I insert the periods in the printf function so it will output to I.E.E.E.?
Instead of writing userAcronym[count++] = userPhrase[i];, you'd like to add both the character and the period:
userAcronym[count++] = userPhrase[i];
userAcronym[count++] = '.';

how can i make this bruteforce algorithm multithreaded?

how can i make this bruteforce algorithm multithreaded? If i launch this it uses only one cpu. How can i parallelize this? It seems impossible. It's ok with fork or with pthread for me. This code makes a bruteforce to invert an hash, it generates all possibile strings, makes the hash and compares with the digest.
#include <stdio.h>
#include <string.h>
#include "attacchi.h"
#include "hash.h"
void iterazione(char *stringa, int index, int lunghezza);
char *checksum,*hashType;
void bruteforce(char digest[],char tipohash[]) {
checksum = malloc(sizeof(char)*1024);
hashType = malloc(sizeof(char)*1024);
strcpy(checksum,digest);
strcpy(hashType,tipohash);
int lunghezza, i;
printf("Inserire la lunghezza massima da testare: ");
scanf("%d", &lunghezza);
char stringa[lunghezza + 1];
memset(stringa, 0, lunghezza + 1);
for (i = 1; i <= lunghezza; i++) {
iterazione(stringa, 0, lunghezza);
}
}
void iterazione(char *stringa, int index, int lunghezza) {
char c;
if (index < (lunghezza - 1)) {
for (c = ' '; c <= '~'; ++c) {
stringa[index] = c;
iterazione(stringa, index + 1, lunghezza);
}
} else {
for (c = ' '; c <= '~'; ++c) {
stringa[index] = c;
stringa[index+1] = '\n';
if(strcmp(hash(stringa,hashType),checksum)==0) {
printf("Trovato!\nhash %s %s -> %s\n", checksum, hashType, stringa);
exit(0);
}
}
}
}
The simplest way to modify your algorithm to take advantage of multiple threads would be instead of starting the recursion with a call to iterazione(stringa, 0, lunghezza), start it with a call that selects the first character from a range then calls iterazione(stringa, 1, lunghezza):
void avvia_iterazione(char iniziale, char finale, int lunghezza)
{
char c;
char stringa[lunghezza + 1] = "";
for (c = iniziale; c <= finale; ++c) {
stringa[0] = c;
iterazione(stringa, 1, lunghezza);
}
}
You then call avvia_iterazione() with different, non-overlapping ranges of characters in each thread (eg. if you have two threads, you might call avvia_iterazione(' ', 'O'); in one and avvia_iterazione('P', '~'); in the other.
(You'll need to make sure that lunghezza >= 2 as well).

Print all binary numbers of length N

I've done this question on leetcode before but wanted to do it in C. Was wondering if anyone could let me know if there is a better way to do it.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void printBinaryLenthHelper(int currentLength, int maxLength, char accum[]) {
if (currentLength == maxLength) {
printf("%s\n", accum);
return;
}
accum[currentLength++] = '0';
printBinaryLenthHelper(currentLength, maxLength, accum);
accum[--currentLength] = '1';
printBinaryLenthHelper(++currentLength, maxLength, accum);
}
void printBinaryLength(int length) {
char accum[length + 1];
printBinaryLenthHelper(0, length, accum);
}
int main() {
printBinaryLength(20);
}
You can avoid recursion by simply iterating from 0 to 2^n -1. This range represents all the numbers with binary length n (assuming smaller numbers are padded with leading zeroes).
Code
#include <stdio.h>
void printBinary(int len) {
//This loop iterates from 0 to 2^len - 1
for(int i = 0; i < 1 << len; ++i) {
//This loop is to print the integer in its binary representation.
for(int j = len - 1; j >= 0; --j) {
// ((1<<j)&i) > 0 evaluates to 1 if the jth bit is set, 0 otherwise
printf("%d", ((1<<j)&i) > 0);
}
printf("\n");
}
}
int main(void) {
// your code goes here
printBinary(10);
return 0;
}
Output
0000000000
0000000001
0000000010
0000000011
0000000100
0000000101
0000000110
0000000111
0000001000
0000001001
0000001010
...
Tested here.
PS: If you do not understand what 1<<j and (1<<j)&j means, read about bitwise operators in C.
There is a problem in your function printBinaryLenthHelper: you do not null terminate the string before passing it to printf. It is also confusing to increment and decrement currentLength as a side effect, just pass the next value in the recursive call.
Here is a corrected version:
void printBinaryLenthHelper(int currentLength, int maxLength, char accum[]) {
if (currentLength == maxLength) {
accum[currentLength] = '\0';
printf("%s\n", accum);
return;
}
accum[currentLength] = '0';
printBinaryLenthHelper(currentLength + 1, maxLength, accum);
accum[currentLength] = '1';
printBinaryLenthHelper(currentLength + 1, maxLength, accum);
}
Note also that the name should be printBinaryLengthHelper.

Function is being called four times per loop when there are only two calls to it

I'm very new to programming in C, and have pretty rusty programming skills overall. In order to learn C and re-orient myself with programming in general, I'm challenging myself to try and make a simple rougelike using ncurses.
I've set up a "log", which I should be able to push messages to - the most recent 10 message should be displayed. In order to test this, I've made it so each time either the player or the very simple randomly-moving mob takes a step, a log message is pushed saying "step [direction]". However, even though they each only take one step, for some reason, four messages are pushed to the log. The second-to-most-recent one is always the actual direction the character moved, and I presume one of the other two is the mob moving, but I don't know the origin of the other two. Does anyone spot anything glaring in my code that might be causing this issue? All help is appreciated, thanks!
(I believe the only major relevant sections to look at should be the main() function, pushToLog(), printLog(), and moveCreature(). That said, there is a chance the problem might be somewhere else. I'm not sure.)
#include <stdlib.h>
#include <stdio.h>
#include <ncurses.h>
#include <unistd.h>
#include <string.h>
#define up 65
#define down 66
#define right 67
#define left 68
#define quit 113
struct creature {
int x;
int y;
int hp;
int maxhp;
};
void setupMap();
struct creature setupCreature();
void moveCreature();
void pushToLog();
void printLog();
int breakFlag = FALSE;
char mapShape[15][15];
char mapFeatures[15][15];
char outputLog[10][60];
int main(int argc, char *argv[]){
struct creature player = setupCreature(4, 4, 100, 100);
struct creature mob = setupCreature(5, 7, 100, 100);
setupMap();
initscr();
noecho();
curs_set(FALSE);
while(1){
for (int i = 0; i < 15; i++){
for (int c = 0; c < 15; c++){
mvprintw(c, i, "%c", mapShape[i][c]);
}
}
mvprintw(player.y, player.x, "%c", '#');
mvprintw(mob.y, mob.x, "%c", 'd');
printLog();
int input = getch();
moveCreature(input, &player);
int mobDir = rand() % (68 + 1 - 65) + 65;
moveCreature(mobDir, &mob);
refresh();
usleep(300);
if (breakFlag == TRUE){
break;
}
}
endwin();
return 0;
}
void moveCreature(int dir, struct creature *subject){
int next;
if (dir == up){
next = (subject->y - 1);
if (mapShape[subject->x][next] != '#'){
subject->y = next;
pushToLog("step up ");
}
}
else if (dir == down){
next = (subject->y + 1);
if (mapShape[subject->x][next] != '#'){
subject->y = next;
pushToLog("step down ");
}
}
else if (dir == right){
next = (subject->x + 1);
if (mapShape[next][subject->y] != '#'){
subject->x = next;
pushToLog("step right ");
}
}
else if (dir == left){
next = (subject->x - 1);
if (mapShape[next][subject->y] != '#'){
subject->x = next;
pushToLog("step left ");
}
}
else if (dir == quit){
breakFlag = TRUE;
}
}
void pushToLog(char string[]){
for (int i = 10; i > 0; i--){
strcpy(outputLog[i], outputLog[i-1]);
}
strcpy(outputLog[0], string);
}
void printLog(){
for (int i = 0; i < 10; i++){
mvprintw(28-i, 0, outputLog[i]);
}
}
struct creature setupCreature(int x,int y,int hp,int maxhp){
struct creature frankenstien;
frankenstien.x = x;
frankenstien.y = y;
frankenstien.hp = hp;
frankenstien.maxhp = maxhp;
return frankenstien;
}
void setupMap(){
for (int i = 0; i < 15; i++){
for (int c = 0; c < 15; c++){
mapShape[i][c] = '.';
}
}
for (int i = 0; i < 15; i++){
mapShape[0][i] = '#';
mapShape[14][i] = '#';
mapShape[i][0] = '#';
mapShape[i][14] = '#';
}
}
Your problem is at the input stage. You expect directional commands via the arrow keys, but those generate multiple bytes per keypress. All but one are invalid as commands.
As a secondary problem, you do not reject invalid commands. You go ahead and move the mob after each command character read, whether that command was valid or not.
The overall upshot is that when you press an arrow key, the program zips through three iterations of the main loop, one right after the other, producing log messages for one valid player move, no log messages for two invalid player moves, and log messages for each of three mob moves.
You could have detected this by logging invalid commands, or by running your program in a debugger.

how to modify detab to accept list of arguments

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define TAB_STOP 8
/* replaces tabs from input with the proper amount of blank spots */
int Detab()
{
int c, x;
int column;
x = column = 0;
while((c=getchar())!=EOF)
{
if(c == '\n') /* reseting counter if newline */
{
putchar(c);
return 1;
}
else if(c!='\t') /* column counts places to tab spot */
{
putchar(c);
column++;
if(column == TAB_STOP)
column = 0;
}
else /* tab */
{
for(x=0; x<TAB_STOP - column; x++)
putchar('_');
column = 0;
}
}
return 0;
}
#define MAX_ARGUMENTS 100
int main(int argc, char *argv[])
{
int i, val = 0;
int nums[MAX_ARGUMENTS];
int x = 0;
for(i = 1; i < argc; i++) {
while(isdigit(*argv[i])) {
val = val * 10 + *argv[i] - '0';
*++argv[i];
}
if(x > MAX_ARGUMENTS - 1)
return 0;
nums[x++] = val;
nums[x] = '\0';
val = 0;
}
while(Detab(nums));
printf("Press any key to continue.\n");
getchar();
return 0;
}
In main i put all the arguments(numbers) inside nums array and then pass it to detab. So now im interested what would be the smart way to edit detab so it works. I'm still trying to figure out for a working pseudocode but i dont really know.
The way i tought it should work is:
if arguments are 5, 8, 10 then a tab inside first 4 characters leads to position 5, in 5 - 7th char leads to pos 8 etc.
In case of a newline, the arguments start all over again from the begining.
The most common way is to have Detab accept a pointer (which points to an element in an array) and the length of that array:
int Detab(int* data, int len); // access data[0] through data[len - 1]
Call it like so:
void example() {
int array[] = {5, 8, 10};
Detab(array, 3);
// or:
Detab(array, sizeof array / sizeof *array); // second parameter evaluates to 3
// without using a magic constant
}
Here's some pseudocode for expanding tabs:
def expandtabs_in_line(line, tabstops, default, space):
result = ""
for c in line:
if c != "\t":
result += c
else:
for stop in tabstops:
if stop > len(result):
result += space * (stop - len(result))
break
else:
result += space * (default - (len(result) % default))
return result
def expandtabs(lines, tabstops=[], default=8):
for line in lines:
yield expandtabs_in_line(line, tabstops, default, " ")
Try it out at codepad.

Resources