commit 58fccbe27a6866e21997e0ed8f2d126a4e30bd36 Author: Luis Rodrigues Date: Sat Oct 17 22:10:27 2026 +0100 primeiro commit com exercicios de Exercism realizados até esta data diff --git a/c/hello-world/.exercism/config.json b/c/hello-world/.exercism/config.json new file mode 100644 index 0000000..0446fdd --- /dev/null +++ b/c/hello-world/.exercism/config.json @@ -0,0 +1,33 @@ +{ + "authors": [ + "JacobMikkelsen" + ], + "contributors": [ + "bcc32", + "benkelaar", + "gea-migration", + "h-3-0", + "kytrinyx", + "patricksjackson", + "QLaille", + "RealBarrettBrown", + "ryanplusplus", + "siebenschlaefer", + "wolf99" + ], + "files": { + "solution": [ + "hello_world.c", + "hello_world.h" + ], + "test": [ + "test_hello_world.c" + ], + "example": [ + ".meta/example.c" + ] + }, + "blurb": "Exercism's classic introductory exercise. Just say \"Hello, World!\".", + "source": "This is an exercise to introduce users to using Exercism", + "source_url": "https://en.wikipedia.org/wiki/%22Hello,_world!%22_program" +} diff --git a/c/hello-world/.exercism/metadata.json b/c/hello-world/.exercism/metadata.json new file mode 100644 index 0000000..b65eed2 --- /dev/null +++ b/c/hello-world/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"c","exercise":"hello-world","id":"952ad4b82fec40d7b8ac31a38e72f9a6","url":"https://exercism.org/tracks/c/exercises/hello-world","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/c/hello-world/HELP.md b/c/hello-world/HELP.md new file mode 100644 index 0000000..6f33384 --- /dev/null +++ b/c/hello-world/HELP.md @@ -0,0 +1,73 @@ +# Help + +## Running the tests + +Get the first test compiling, linking and passing by following the [three rules of test-driven development][3-tdd-rules]. + +The included makefile can be used to create and run the tests using the `test` task. + +```console +$ make test +``` + +Create just the functions you need to satisfy any compiler errors and get the test to fail. +Then write just enough code to get the test to pass. +Once you've done that, move onto the next test. + +As you progress through the tests, take the time to refactor your implementation for readability and expressiveness and then go on to the next test. + +Try to use standard C99 facilities in preference to writing your own low-level algorithms or facilities by hand. + +## Checking for memory leaks + +The makefile comes also with a build that checks some common mistakes regarding memory leaks and out of bound access to arrays. +To run these checks, use the following at the command line: + +```console +$ make memcheck +``` + +[3-tdd-rules]: https://blog.cleancoder.com/uncle-bob/2014/12/17/TheCyclesOfTDD.html + +## Submitting your solution + +You can submit your solution using the `exercism submit hello_world.c hello_world.h` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [C track's documentation](https://exercism.org/docs/tracks/c) +- The [C track's programming category on the forum](https://forum.exercism.org/c/programming/c) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Make sure you have read the [C track-specific documentation][c-track] on the Exercism site. +This covers the basic information on setting up the development environment expected by the exercises. + +## Submitting Incomplete Solutions + +If you are struggling with a particular exercise, it is possible to submit an incomplete solution so you can see how others have completed the exercise. + +## Resources + +To get help if having trouble, you can use the following resources: + +- [StackOverflow][] can be used to search for your problem and see if it has been answered already. You can also ask and answer questions. +- [CPPReference][] can be used to look up information on C concepts, operators, types, standard library functions and more. +- [TutorialsPoint][] has similar content as CPPReference in its C programming section. +- [The C Programming][K&R] book by K&R is the original source of the language and is still useful today. + +[c-track]: https://exercism.org/docs/tracks/c +[stackoverflow]: http://stackoverflow.com/questions/tagged/c +[cppreference]: https://en.cppreference.com/w/c +[tutorialspoint]: https://www.tutorialspoint.com/cprogramming/ +[K&R]: https://www.amazon.com/Programming-Language-2nd-Brian-Kernighan/dp/0131103628/ \ No newline at end of file diff --git a/c/hello-world/README.md b/c/hello-world/README.md new file mode 100644 index 0000000..fdacf69 --- /dev/null +++ b/c/hello-world/README.md @@ -0,0 +1,45 @@ +# Hello World + +Welcome to Hello World on Exercism's C Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Instructions + +The classical introductory exercise. +Just say "Hello, World!". + +["Hello, World!"][hello-world] is the traditional first program for beginning programming in a new language or environment. + +The objectives are simple: + +- Modify the provided code so that it produces the string "Hello, World!". +- Run the test suite and make sure that it succeeds. +- Submit your solution and check it at the website. + +If everything goes well, you will be ready to fetch your first real exercise. + +[hello-world]: https://en.wikipedia.org/wiki/%22Hello,_world!%22_program + +## Source + +### Created by + +- @JacobMikkelsen + +### Contributed to by + +- @bcc32 +- @benkelaar +- @gea-migration +- @h-3-0 +- @kytrinyx +- @patricksjackson +- @QLaille +- @RealBarrettBrown +- @ryanplusplus +- @siebenschlaefer +- @wolf99 + +### Based on + +This is an exercise to introduce users to using Exercism - https://en.wikipedia.org/wiki/%22Hello,_world!%22_program \ No newline at end of file diff --git a/c/hello-world/hello_world.c b/c/hello-world/hello_world.c new file mode 100644 index 0000000..f4fa063 --- /dev/null +++ b/c/hello-world/hello_world.c @@ -0,0 +1,4 @@ +#include "hello_world.h" + +// Define the function itself. +const char *hello(void) { return "Hello, World!"; } diff --git a/c/hello-world/hello_world.h b/c/hello-world/hello_world.h new file mode 100644 index 0000000..70c0bb5 --- /dev/null +++ b/c/hello-world/hello_world.h @@ -0,0 +1,14 @@ +// This is called an include guard, which ensures that the header is only +// included once. You could alternatively use '#pragma once'. See +// https://en.wikipedia.org/wiki/Include_guard. +#ifndef HELLO_WORLD_H +#define HELLO_WORLD_H + +// Declare the 'hello()' function, which takes no arguments and returns a +// 'const char *', i.e. a pointer to a character (in this case the first +// character in a string). The function itself is defined in the hello_world.c +// source file. This function is called by the test case(s) in the test source +// file test_hello_world.c. +const char *hello(void); + +#endif diff --git a/c/hello-world/makefile b/c/hello-world/makefile new file mode 100644 index 0000000..d47331f --- /dev/null +++ b/c/hello-world/makefile @@ -0,0 +1,37 @@ +### If you wish to use extra libraries (math.h for instance), +### add their flags here (-lm in our case) in the "LIBS" variable. + +LIBS = -lm + +### +CFLAGS = -std=c99 +CFLAGS += -g +CFLAGS += -Wall +CFLAGS += -Wextra +CFLAGS += -pedantic +CFLAGS += -Werror +CFLAGS += -Wmissing-declarations +CFLAGS += -DUNITY_SUPPORT_64 -DUNITY_OUTPUT_COLOR + +ASANFLAGS = -fsanitize=address +ASANFLAGS += -fno-common +ASANFLAGS += -fno-omit-frame-pointer + +.PHONY: test +test: tests.out + @./tests.out + +.PHONY: memcheck +memcheck: ./*.c ./*.h + @echo Compiling $@ + @$(CC) $(ASANFLAGS) $(CFLAGS) test-framework/unity.c ./*.c -o memcheck.out $(LIBS) + @./memcheck.out + @echo "Memory check passed" + +.PHONY: clean +clean: + rm -rf *.o *.out *.out.dSYM + +tests.out: ./*.c ./*.h + @echo Compiling $@ + @$(CC) $(CFLAGS) test-framework/unity.c ./*.c -o tests.out $(LIBS) diff --git a/c/hello-world/test-framework/unity.c b/c/hello-world/test-framework/unity.c new file mode 100644 index 0000000..be3528f --- /dev/null +++ b/c/hello-world/test-framework/unity.c @@ -0,0 +1,2110 @@ +/* ========================================================================= + Unity Project - A Test Framework for C + Copyright (c) 2007-21 Mike Karlesky, Mark VanderVoord, Greg Williams + [Released under MIT License. Please refer to license.txt for details] +============================================================================ */ + +#include "unity.h" +#include + +#ifdef AVR +#include +#else +#define PROGMEM +#endif + +/* If omitted from header, declare overrideable prototypes here so they're ready for use */ +#ifdef UNITY_OMIT_OUTPUT_CHAR_HEADER_DECLARATION +void UNITY_OUTPUT_CHAR(int); +#endif + +/* Helpful macros for us to use here in Assert functions */ +#define UNITY_FAIL_AND_BAIL { Unity.CurrentTestFailed = 1; UNITY_OUTPUT_FLUSH(); TEST_ABORT(); } +#define UNITY_IGNORE_AND_BAIL { Unity.CurrentTestIgnored = 1; UNITY_OUTPUT_FLUSH(); TEST_ABORT(); } +#define RETURN_IF_FAIL_OR_IGNORE if (Unity.CurrentTestFailed || Unity.CurrentTestIgnored) TEST_ABORT() + +struct UNITY_STORAGE_T Unity; + +#ifdef UNITY_OUTPUT_COLOR +const char PROGMEM UnityStrOk[] = "\033[42mOK\033[00m"; +const char PROGMEM UnityStrPass[] = "\033[42mPASS\033[00m"; +const char PROGMEM UnityStrFail[] = "\033[41mFAIL\033[00m"; +const char PROGMEM UnityStrIgnore[] = "\033[43mIGNORE\033[00m"; +#else +const char PROGMEM UnityStrOk[] = "OK"; +const char PROGMEM UnityStrPass[] = "PASS"; +const char PROGMEM UnityStrFail[] = "FAIL"; +const char PROGMEM UnityStrIgnore[] = "IGNORE"; +#endif +static const char PROGMEM UnityStrNull[] = "NULL"; +static const char PROGMEM UnityStrSpacer[] = ". "; +static const char PROGMEM UnityStrExpected[] = " Expected "; +static const char PROGMEM UnityStrWas[] = " Was "; +static const char PROGMEM UnityStrGt[] = " to be greater than "; +static const char PROGMEM UnityStrLt[] = " to be less than "; +static const char PROGMEM UnityStrOrEqual[] = "or equal to "; +static const char PROGMEM UnityStrNotEqual[] = " to be not equal to "; +static const char PROGMEM UnityStrElement[] = " Element "; +static const char PROGMEM UnityStrByte[] = " Byte "; +static const char PROGMEM UnityStrMemory[] = " Memory Mismatch."; +static const char PROGMEM UnityStrDelta[] = " Values Not Within Delta "; +static const char PROGMEM UnityStrPointless[] = " You Asked Me To Compare Nothing, Which Was Pointless."; +static const char PROGMEM UnityStrNullPointerForExpected[] = " Expected pointer to be NULL"; +static const char PROGMEM UnityStrNullPointerForActual[] = " Actual pointer was NULL"; +#ifndef UNITY_EXCLUDE_FLOAT +static const char PROGMEM UnityStrNot[] = "Not "; +static const char PROGMEM UnityStrInf[] = "Infinity"; +static const char PROGMEM UnityStrNegInf[] = "Negative Infinity"; +static const char PROGMEM UnityStrNaN[] = "NaN"; +static const char PROGMEM UnityStrDet[] = "Determinate"; +static const char PROGMEM UnityStrInvalidFloatTrait[] = "Invalid Float Trait"; +#endif +const char PROGMEM UnityStrErrShorthand[] = "Unity Shorthand Support Disabled"; +const char PROGMEM UnityStrErrFloat[] = "Unity Floating Point Disabled"; +const char PROGMEM UnityStrErrDouble[] = "Unity Double Precision Disabled"; +const char PROGMEM UnityStrErr64[] = "Unity 64-bit Support Disabled"; +static const char PROGMEM UnityStrBreaker[] = "-----------------------"; +static const char PROGMEM UnityStrResultsTests[] = " Tests "; +static const char PROGMEM UnityStrResultsFailures[] = " Failures "; +static const char PROGMEM UnityStrResultsIgnored[] = " Ignored "; +#ifndef UNITY_EXCLUDE_DETAILS +static const char PROGMEM UnityStrDetail1Name[] = UNITY_DETAIL1_NAME " "; +static const char PROGMEM UnityStrDetail2Name[] = " " UNITY_DETAIL2_NAME " "; +#endif +/*----------------------------------------------- + * Pretty Printers & Test Result Output Handlers + *-----------------------------------------------*/ + +/*-----------------------------------------------*/ +/* Local helper function to print characters. */ +static void UnityPrintChar(const char* pch) +{ + /* printable characters plus CR & LF are printed */ + if ((*pch <= 126) && (*pch >= 32)) + { + UNITY_OUTPUT_CHAR(*pch); + } + /* write escaped carriage returns */ + else if (*pch == 13) + { + UNITY_OUTPUT_CHAR('\\'); + UNITY_OUTPUT_CHAR('r'); + } + /* write escaped line feeds */ + else if (*pch == 10) + { + UNITY_OUTPUT_CHAR('\\'); + UNITY_OUTPUT_CHAR('n'); + } + /* unprintable characters are shown as codes */ + else + { + UNITY_OUTPUT_CHAR('\\'); + UNITY_OUTPUT_CHAR('x'); + UnityPrintNumberHex((UNITY_UINT)*pch, 2); + } +} + +/*-----------------------------------------------*/ +/* Local helper function to print ANSI escape strings e.g. "\033[42m". */ +#ifdef UNITY_OUTPUT_COLOR +static UNITY_UINT UnityPrintAnsiEscapeString(const char* string) +{ + const char* pch = string; + UNITY_UINT count = 0; + + while (*pch && (*pch != 'm')) + { + UNITY_OUTPUT_CHAR(*pch); + pch++; + count++; + } + UNITY_OUTPUT_CHAR('m'); + count++; + + return count; +} +#endif + +/*-----------------------------------------------*/ +void UnityPrint(const char* string) +{ + const char* pch = string; + + if (pch != NULL) + { + while (*pch) + { +#ifdef UNITY_OUTPUT_COLOR + /* print ANSI escape code */ + if ((*pch == 27) && (*(pch + 1) == '[')) + { + pch += UnityPrintAnsiEscapeString(pch); + continue; + } +#endif + UnityPrintChar(pch); + pch++; + } + } +} +/*-----------------------------------------------*/ +void UnityPrintLen(const char* string, const UNITY_UINT32 length) +{ + const char* pch = string; + + if (pch != NULL) + { + while (*pch && ((UNITY_UINT32)(pch - string) < length)) + { + /* printable characters plus CR & LF are printed */ + if ((*pch <= 126) && (*pch >= 32)) + { + UNITY_OUTPUT_CHAR(*pch); + } + /* write escaped carriage returns */ + else if (*pch == 13) + { + UNITY_OUTPUT_CHAR('\\'); + UNITY_OUTPUT_CHAR('r'); + } + /* write escaped line feeds */ + else if (*pch == 10) + { + UNITY_OUTPUT_CHAR('\\'); + UNITY_OUTPUT_CHAR('n'); + } + /* unprintable characters are shown as codes */ + else + { + UNITY_OUTPUT_CHAR('\\'); + UNITY_OUTPUT_CHAR('x'); + UnityPrintNumberHex((UNITY_UINT)*pch, 2); + } + pch++; + } + } +} + +/*-----------------------------------------------*/ +void UnityPrintNumberByStyle(const UNITY_INT number, const UNITY_DISPLAY_STYLE_T style) +{ + if ((style & UNITY_DISPLAY_RANGE_INT) == UNITY_DISPLAY_RANGE_INT) + { + if (style == UNITY_DISPLAY_STYLE_CHAR) + { + /* printable characters plus CR & LF are printed */ + UNITY_OUTPUT_CHAR('\''); + if ((number <= 126) && (number >= 32)) + { + UNITY_OUTPUT_CHAR((int)number); + } + /* write escaped carriage returns */ + else if (number == 13) + { + UNITY_OUTPUT_CHAR('\\'); + UNITY_OUTPUT_CHAR('r'); + } + /* write escaped line feeds */ + else if (number == 10) + { + UNITY_OUTPUT_CHAR('\\'); + UNITY_OUTPUT_CHAR('n'); + } + /* unprintable characters are shown as codes */ + else + { + UNITY_OUTPUT_CHAR('\\'); + UNITY_OUTPUT_CHAR('x'); + UnityPrintNumberHex((UNITY_UINT)number, 2); + } + UNITY_OUTPUT_CHAR('\''); + } + else + { + UnityPrintNumber(number); + } + } + else if ((style & UNITY_DISPLAY_RANGE_UINT) == UNITY_DISPLAY_RANGE_UINT) + { + UnityPrintNumberUnsigned((UNITY_UINT)number); + } + else + { + UNITY_OUTPUT_CHAR('0'); + UNITY_OUTPUT_CHAR('x'); + UnityPrintNumberHex((UNITY_UINT)number, (char)((style & 0xF) * 2)); + } +} + +/*-----------------------------------------------*/ +void UnityPrintNumber(const UNITY_INT number_to_print) +{ + UNITY_UINT number = (UNITY_UINT)number_to_print; + + if (number_to_print < 0) + { + /* A negative number, including MIN negative */ + UNITY_OUTPUT_CHAR('-'); + number = (~number) + 1; + } + UnityPrintNumberUnsigned(number); +} + +/*----------------------------------------------- + * basically do an itoa using as little ram as possible */ +void UnityPrintNumberUnsigned(const UNITY_UINT number) +{ + UNITY_UINT divisor = 1; + + /* figure out initial divisor */ + while (number / divisor > 9) + { + divisor *= 10; + } + + /* now mod and print, then divide divisor */ + do + { + UNITY_OUTPUT_CHAR((char)('0' + (number / divisor % 10))); + divisor /= 10; + } while (divisor > 0); +} + +/*-----------------------------------------------*/ +void UnityPrintNumberHex(const UNITY_UINT number, const char nibbles_to_print) +{ + int nibble; + char nibbles = nibbles_to_print; + + if ((unsigned)nibbles > UNITY_MAX_NIBBLES) + { + nibbles = UNITY_MAX_NIBBLES; + } + + while (nibbles > 0) + { + nibbles--; + nibble = (int)(number >> (nibbles * 4)) & 0x0F; + if (nibble <= 9) + { + UNITY_OUTPUT_CHAR((char)('0' + nibble)); + } + else + { + UNITY_OUTPUT_CHAR((char)('A' - 10 + nibble)); + } + } +} + +/*-----------------------------------------------*/ +void UnityPrintMask(const UNITY_UINT mask, const UNITY_UINT number) +{ + UNITY_UINT current_bit = (UNITY_UINT)1 << (UNITY_INT_WIDTH - 1); + UNITY_INT32 i; + + for (i = 0; i < UNITY_INT_WIDTH; i++) + { + if (current_bit & mask) + { + if (current_bit & number) + { + UNITY_OUTPUT_CHAR('1'); + } + else + { + UNITY_OUTPUT_CHAR('0'); + } + } + else + { + UNITY_OUTPUT_CHAR('X'); + } + current_bit = current_bit >> 1; + } +} + +/*-----------------------------------------------*/ +#ifndef UNITY_EXCLUDE_FLOAT_PRINT +/* + * This function prints a floating-point value in a format similar to + * printf("%.7g") on a single-precision machine or printf("%.9g") on a + * double-precision machine. The 7th digit won't always be totally correct + * in single-precision operation (for that level of accuracy, a more + * complicated algorithm would be needed). + */ +void UnityPrintFloat(const UNITY_DOUBLE input_number) +{ +#ifdef UNITY_INCLUDE_DOUBLE + static const int sig_digits = 9; + static const UNITY_INT32 min_scaled = 100000000; + static const UNITY_INT32 max_scaled = 1000000000; +#else + static const int sig_digits = 7; + static const UNITY_INT32 min_scaled = 1000000; + static const UNITY_INT32 max_scaled = 10000000; +#endif + + UNITY_DOUBLE number = input_number; + + /* print minus sign (does not handle negative zero) */ + if (number < 0.0f) + { + UNITY_OUTPUT_CHAR('-'); + number = -number; + } + + /* handle zero, NaN, and +/- infinity */ + if (number == 0.0f) + { + UnityPrint("0"); + } + else if (isnan(number)) + { + UnityPrint("nan"); + } + else if (isinf(number)) + { + UnityPrint("inf"); + } + else + { + UNITY_INT32 n_int = 0, n; + int exponent = 0; + int decimals, digits; + char buf[16] = {0}; + + /* + * Scale up or down by powers of 10. To minimize rounding error, + * start with a factor/divisor of 10^10, which is the largest + * power of 10 that can be represented exactly. Finally, compute + * (exactly) the remaining power of 10 and perform one more + * multiplication or division. + */ + if (number < 1.0f) + { + UNITY_DOUBLE factor = 1.0f; + + while (number < (UNITY_DOUBLE)max_scaled / 1e10f) { number *= 1e10f; exponent -= 10; } + while (number * factor < (UNITY_DOUBLE)min_scaled) { factor *= 10.0f; exponent--; } + + number *= factor; + } + else if (number > (UNITY_DOUBLE)max_scaled) + { + UNITY_DOUBLE divisor = 1.0f; + + while (number > (UNITY_DOUBLE)min_scaled * 1e10f) { number /= 1e10f; exponent += 10; } + while (number / divisor > (UNITY_DOUBLE)max_scaled) { divisor *= 10.0f; exponent++; } + + number /= divisor; + } + else + { + /* + * In this range, we can split off the integer part before + * doing any multiplications. This reduces rounding error by + * freeing up significant bits in the fractional part. + */ + UNITY_DOUBLE factor = 1.0f; + n_int = (UNITY_INT32)number; + number -= (UNITY_DOUBLE)n_int; + + while (n_int < min_scaled) { n_int *= 10; factor *= 10.0f; exponent--; } + + number *= factor; + } + + /* round to nearest integer */ + n = ((UNITY_INT32)(number + number) + 1) / 2; + +#ifndef UNITY_ROUND_TIES_AWAY_FROM_ZERO + /* round to even if exactly between two integers */ + if ((n & 1) && (((UNITY_DOUBLE)n - number) == 0.5f)) + n--; +#endif + + n += n_int; + + if (n >= max_scaled) + { + n = min_scaled; + exponent++; + } + + /* determine where to place decimal point */ + decimals = ((exponent <= 0) && (exponent >= -(sig_digits + 3))) ? (-exponent) : (sig_digits - 1); + exponent += decimals; + + /* truncate trailing zeroes after decimal point */ + while ((decimals > 0) && ((n % 10) == 0)) + { + n /= 10; + decimals--; + } + + /* build up buffer in reverse order */ + digits = 0; + while ((n != 0) || (digits < (decimals + 1))) + { + buf[digits++] = (char)('0' + n % 10); + n /= 10; + } + while (digits > 0) + { + if (digits == decimals) { UNITY_OUTPUT_CHAR('.'); } + UNITY_OUTPUT_CHAR(buf[--digits]); + } + + /* print exponent if needed */ + if (exponent != 0) + { + UNITY_OUTPUT_CHAR('e'); + + if (exponent < 0) + { + UNITY_OUTPUT_CHAR('-'); + exponent = -exponent; + } + else + { + UNITY_OUTPUT_CHAR('+'); + } + + digits = 0; + while ((exponent != 0) || (digits < 2)) + { + buf[digits++] = (char)('0' + exponent % 10); + exponent /= 10; + } + while (digits > 0) + { + UNITY_OUTPUT_CHAR(buf[--digits]); + } + } + } +} +#endif /* ! UNITY_EXCLUDE_FLOAT_PRINT */ + +/*-----------------------------------------------*/ +static void UnityTestResultsBegin(const char* file, const UNITY_LINE_TYPE line) +{ +#ifdef UNITY_OUTPUT_FOR_ECLIPSE + UNITY_OUTPUT_CHAR('('); + UnityPrint(file); + UNITY_OUTPUT_CHAR(':'); + UnityPrintNumber((UNITY_INT)line); + UNITY_OUTPUT_CHAR(')'); + UNITY_OUTPUT_CHAR(' '); + UnityPrint(Unity.CurrentTestName); + UNITY_OUTPUT_CHAR(':'); +#else +#ifdef UNITY_OUTPUT_FOR_IAR_WORKBENCH + UnityPrint("'); + UnityPrint(Unity.CurrentTestName); + UnityPrint(" "); +#else +#ifdef UNITY_OUTPUT_FOR_QT_CREATOR + UnityPrint("file://"); + UnityPrint(file); + UNITY_OUTPUT_CHAR(':'); + UnityPrintNumber((UNITY_INT)line); + UNITY_OUTPUT_CHAR(' '); + UnityPrint(Unity.CurrentTestName); + UNITY_OUTPUT_CHAR(':'); +#else + UnityPrint(file); + UNITY_OUTPUT_CHAR(':'); + UnityPrintNumber((UNITY_INT)line); + UNITY_OUTPUT_CHAR(':'); + UnityPrint(Unity.CurrentTestName); + UNITY_OUTPUT_CHAR(':'); +#endif +#endif +#endif +} + +/*-----------------------------------------------*/ +static void UnityTestResultsFailBegin(const UNITY_LINE_TYPE line) +{ + UnityTestResultsBegin(Unity.TestFile, line); + UnityPrint(UnityStrFail); + UNITY_OUTPUT_CHAR(':'); +} + +/*-----------------------------------------------*/ +void UnityConcludeTest(void) +{ + if (Unity.CurrentTestIgnored) + { + Unity.TestIgnores++; + } + else if (!Unity.CurrentTestFailed) + { + UnityTestResultsBegin(Unity.TestFile, Unity.CurrentTestLineNumber); + UnityPrint(UnityStrPass); + } + else + { + Unity.TestFailures++; + } + + Unity.CurrentTestFailed = 0; + Unity.CurrentTestIgnored = 0; + UNITY_PRINT_EXEC_TIME(); + UNITY_PRINT_EOL(); + UNITY_FLUSH_CALL(); +} + +/*-----------------------------------------------*/ +static void UnityAddMsgIfSpecified(const char* msg) +{ + if (msg) + { + UnityPrint(UnityStrSpacer); + +#ifdef UNITY_PRINT_TEST_CONTEXT + UNITY_PRINT_TEST_CONTEXT(); +#endif +#ifndef UNITY_EXCLUDE_DETAILS + if (Unity.CurrentDetail1) + { + UnityPrint(UnityStrDetail1Name); + UnityPrint(Unity.CurrentDetail1); + if (Unity.CurrentDetail2) + { + UnityPrint(UnityStrDetail2Name); + UnityPrint(Unity.CurrentDetail2); + } + UnityPrint(UnityStrSpacer); + } +#endif + UnityPrint(msg); + } +} + +/*-----------------------------------------------*/ +static void UnityPrintExpectedAndActualStrings(const char* expected, const char* actual) +{ + UnityPrint(UnityStrExpected); + if (expected != NULL) + { + UNITY_OUTPUT_CHAR('\''); + UnityPrint(expected); + UNITY_OUTPUT_CHAR('\''); + } + else + { + UnityPrint(UnityStrNull); + } + UnityPrint(UnityStrWas); + if (actual != NULL) + { + UNITY_OUTPUT_CHAR('\''); + UnityPrint(actual); + UNITY_OUTPUT_CHAR('\''); + } + else + { + UnityPrint(UnityStrNull); + } +} + +/*-----------------------------------------------*/ +static void UnityPrintExpectedAndActualStringsLen(const char* expected, + const char* actual, + const UNITY_UINT32 length) +{ + UnityPrint(UnityStrExpected); + if (expected != NULL) + { + UNITY_OUTPUT_CHAR('\''); + UnityPrintLen(expected, length); + UNITY_OUTPUT_CHAR('\''); + } + else + { + UnityPrint(UnityStrNull); + } + UnityPrint(UnityStrWas); + if (actual != NULL) + { + UNITY_OUTPUT_CHAR('\''); + UnityPrintLen(actual, length); + UNITY_OUTPUT_CHAR('\''); + } + else + { + UnityPrint(UnityStrNull); + } +} + +/*----------------------------------------------- + * Assertion & Control Helpers + *-----------------------------------------------*/ + +/*-----------------------------------------------*/ +static int UnityIsOneArrayNull(UNITY_INTERNAL_PTR expected, + UNITY_INTERNAL_PTR actual, + const UNITY_LINE_TYPE lineNumber, + const char* msg) +{ + /* Both are NULL or same pointer */ + if (expected == actual) { return 0; } + + /* print and return true if just expected is NULL */ + if (expected == NULL) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrNullPointerForExpected); + UnityAddMsgIfSpecified(msg); + return 1; + } + + /* print and return true if just actual is NULL */ + if (actual == NULL) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrNullPointerForActual); + UnityAddMsgIfSpecified(msg); + return 1; + } + + return 0; /* return false if neither is NULL */ +} + +/*----------------------------------------------- + * Assertion Functions + *-----------------------------------------------*/ + +/*-----------------------------------------------*/ +void UnityAssertBits(const UNITY_INT mask, + const UNITY_INT expected, + const UNITY_INT actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber) +{ + RETURN_IF_FAIL_OR_IGNORE; + + if ((mask & expected) != (mask & actual)) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrExpected); + UnityPrintMask((UNITY_UINT)mask, (UNITY_UINT)expected); + UnityPrint(UnityStrWas); + UnityPrintMask((UNITY_UINT)mask, (UNITY_UINT)actual); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } +} + +/*-----------------------------------------------*/ +void UnityAssertEqualNumber(const UNITY_INT expected, + const UNITY_INT actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_DISPLAY_STYLE_T style) +{ + RETURN_IF_FAIL_OR_IGNORE; + + if (expected != actual) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrExpected); + UnityPrintNumberByStyle(expected, style); + UnityPrint(UnityStrWas); + UnityPrintNumberByStyle(actual, style); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } +} + +/*-----------------------------------------------*/ +void UnityAssertGreaterOrLessOrEqualNumber(const UNITY_INT threshold, + const UNITY_INT actual, + const UNITY_COMPARISON_T compare, + const char *msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_DISPLAY_STYLE_T style) +{ + int failed = 0; + RETURN_IF_FAIL_OR_IGNORE; + + if ((threshold == actual) && (compare & UNITY_EQUAL_TO)) { return; } + if ((threshold == actual)) { failed = 1; } + + if ((style & UNITY_DISPLAY_RANGE_INT) == UNITY_DISPLAY_RANGE_INT) + { + if ((actual > threshold) && (compare & UNITY_SMALLER_THAN)) { failed = 1; } + if ((actual < threshold) && (compare & UNITY_GREATER_THAN)) { failed = 1; } + } + else /* UINT or HEX */ + { + if (((UNITY_UINT)actual > (UNITY_UINT)threshold) && (compare & UNITY_SMALLER_THAN)) { failed = 1; } + if (((UNITY_UINT)actual < (UNITY_UINT)threshold) && (compare & UNITY_GREATER_THAN)) { failed = 1; } + } + + if (failed) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrExpected); + UnityPrintNumberByStyle(actual, style); + if (compare & UNITY_GREATER_THAN) { UnityPrint(UnityStrGt); } + if (compare & UNITY_SMALLER_THAN) { UnityPrint(UnityStrLt); } + if (compare & UNITY_EQUAL_TO) { UnityPrint(UnityStrOrEqual); } + if (compare == UNITY_NOT_EQUAL) { UnityPrint(UnityStrNotEqual); } + UnityPrintNumberByStyle(threshold, style); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } +} + +#define UnityPrintPointlessAndBail() \ +{ \ + UnityTestResultsFailBegin(lineNumber); \ + UnityPrint(UnityStrPointless); \ + UnityAddMsgIfSpecified(msg); \ + UNITY_FAIL_AND_BAIL; } + +/*-----------------------------------------------*/ +void UnityAssertEqualIntArray(UNITY_INTERNAL_PTR expected, + UNITY_INTERNAL_PTR actual, + const UNITY_UINT32 num_elements, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_DISPLAY_STYLE_T style, + const UNITY_FLAGS_T flags) +{ + UNITY_UINT32 elements = num_elements; + unsigned int length = style & 0xF; + unsigned int increment = 0; + + RETURN_IF_FAIL_OR_IGNORE; + + if (num_elements == 0) + { + UnityPrintPointlessAndBail(); + } + + if (expected == actual) + { + return; /* Both are NULL or same pointer */ + } + + if (UnityIsOneArrayNull(expected, actual, lineNumber, msg)) + { + UNITY_FAIL_AND_BAIL; + } + + while ((elements > 0) && (elements--)) + { + UNITY_INT expect_val; + UNITY_INT actual_val; + + switch (length) + { + case 1: + expect_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT8*)expected; + actual_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT8*)actual; + increment = sizeof(UNITY_INT8); + break; + + case 2: + expect_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT16*)expected; + actual_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT16*)actual; + increment = sizeof(UNITY_INT16); + break; + +#ifdef UNITY_SUPPORT_64 + case 8: + expect_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT64*)expected; + actual_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT64*)actual; + increment = sizeof(UNITY_INT64); + break; +#endif + + default: /* default is length 4 bytes */ + case 4: + expect_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT32*)expected; + actual_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT32*)actual; + increment = sizeof(UNITY_INT32); + length = 4; + break; + } + + if (expect_val != actual_val) + { + if ((style & UNITY_DISPLAY_RANGE_UINT) && (length < (UNITY_INT_WIDTH / 8))) + { /* For UINT, remove sign extension (padding 1's) from signed type casts above */ + UNITY_INT mask = 1; + mask = (mask << 8 * length) - 1; + expect_val &= mask; + actual_val &= mask; + } + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrElement); + UnityPrintNumberUnsigned(num_elements - elements - 1); + UnityPrint(UnityStrExpected); + UnityPrintNumberByStyle(expect_val, style); + UnityPrint(UnityStrWas); + UnityPrintNumberByStyle(actual_val, style); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } + /* Walk through array by incrementing the pointers */ + if (flags == UNITY_ARRAY_TO_ARRAY) + { + expected = (UNITY_INTERNAL_PTR)((const char*)expected + increment); + } + actual = (UNITY_INTERNAL_PTR)((const char*)actual + increment); + } +} + +/*-----------------------------------------------*/ +#ifndef UNITY_EXCLUDE_FLOAT +/* Wrap this define in a function with variable types as float or double */ +#define UNITY_FLOAT_OR_DOUBLE_WITHIN(delta, expected, actual, diff) \ + if (isinf(expected) && isinf(actual) && (((expected) < 0) == ((actual) < 0))) return 1; \ + if (UNITY_NAN_CHECK) return 1; \ + (diff) = (actual) - (expected); \ + if ((diff) < 0) (diff) = -(diff); \ + if ((delta) < 0) (delta) = -(delta); \ + return !(isnan(diff) || isinf(diff) || ((diff) > (delta))) + /* This first part of this condition will catch any NaN or Infinite values */ +#ifndef UNITY_NAN_NOT_EQUAL_NAN + #define UNITY_NAN_CHECK isnan(expected) && isnan(actual) +#else + #define UNITY_NAN_CHECK 0 +#endif + +#ifndef UNITY_EXCLUDE_FLOAT_PRINT + #define UNITY_PRINT_EXPECTED_AND_ACTUAL_FLOAT(expected, actual) \ + { \ + UnityPrint(UnityStrExpected); \ + UnityPrintFloat(expected); \ + UnityPrint(UnityStrWas); \ + UnityPrintFloat(actual); } +#else + #define UNITY_PRINT_EXPECTED_AND_ACTUAL_FLOAT(expected, actual) \ + UnityPrint(UnityStrDelta) +#endif /* UNITY_EXCLUDE_FLOAT_PRINT */ + +/*-----------------------------------------------*/ +static int UnityFloatsWithin(UNITY_FLOAT delta, UNITY_FLOAT expected, UNITY_FLOAT actual) +{ + UNITY_FLOAT diff; + UNITY_FLOAT_OR_DOUBLE_WITHIN(delta, expected, actual, diff); +} + +/*-----------------------------------------------*/ +void UnityAssertEqualFloatArray(UNITY_PTR_ATTRIBUTE const UNITY_FLOAT* expected, + UNITY_PTR_ATTRIBUTE const UNITY_FLOAT* actual, + const UNITY_UINT32 num_elements, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_FLAGS_T flags) +{ + UNITY_UINT32 elements = num_elements; + UNITY_PTR_ATTRIBUTE const UNITY_FLOAT* ptr_expected = expected; + UNITY_PTR_ATTRIBUTE const UNITY_FLOAT* ptr_actual = actual; + + RETURN_IF_FAIL_OR_IGNORE; + + if (elements == 0) + { + UnityPrintPointlessAndBail(); + } + + if (expected == actual) + { + return; /* Both are NULL or same pointer */ + } + + if (UnityIsOneArrayNull((UNITY_INTERNAL_PTR)expected, (UNITY_INTERNAL_PTR)actual, lineNumber, msg)) + { + UNITY_FAIL_AND_BAIL; + } + + while (elements--) + { + if (!UnityFloatsWithin(*ptr_expected * UNITY_FLOAT_PRECISION, *ptr_expected, *ptr_actual)) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrElement); + UnityPrintNumberUnsigned(num_elements - elements - 1); + UNITY_PRINT_EXPECTED_AND_ACTUAL_FLOAT((UNITY_DOUBLE)*ptr_expected, (UNITY_DOUBLE)*ptr_actual); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } + if (flags == UNITY_ARRAY_TO_ARRAY) + { + ptr_expected++; + } + ptr_actual++; + } +} + +/*-----------------------------------------------*/ +void UnityAssertFloatsWithin(const UNITY_FLOAT delta, + const UNITY_FLOAT expected, + const UNITY_FLOAT actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber) +{ + RETURN_IF_FAIL_OR_IGNORE; + + + if (!UnityFloatsWithin(delta, expected, actual)) + { + UnityTestResultsFailBegin(lineNumber); + UNITY_PRINT_EXPECTED_AND_ACTUAL_FLOAT((UNITY_DOUBLE)expected, (UNITY_DOUBLE)actual); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } +} + +/*-----------------------------------------------*/ +void UnityAssertFloatSpecial(const UNITY_FLOAT actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_FLOAT_TRAIT_T style) +{ + const char* trait_names[] = {UnityStrInf, UnityStrNegInf, UnityStrNaN, UnityStrDet}; + UNITY_INT should_be_trait = ((UNITY_INT)style & 1); + UNITY_INT is_trait = !should_be_trait; + UNITY_INT trait_index = (UNITY_INT)(style >> 1); + + RETURN_IF_FAIL_OR_IGNORE; + + switch (style) + { + case UNITY_FLOAT_IS_INF: + case UNITY_FLOAT_IS_NOT_INF: + is_trait = isinf(actual) && (actual > 0); + break; + case UNITY_FLOAT_IS_NEG_INF: + case UNITY_FLOAT_IS_NOT_NEG_INF: + is_trait = isinf(actual) && (actual < 0); + break; + + case UNITY_FLOAT_IS_NAN: + case UNITY_FLOAT_IS_NOT_NAN: + is_trait = isnan(actual) ? 1 : 0; + break; + + case UNITY_FLOAT_IS_DET: /* A determinate number is non infinite and not NaN. */ + case UNITY_FLOAT_IS_NOT_DET: + is_trait = !isinf(actual) && !isnan(actual); + break; + + default: /* including UNITY_FLOAT_INVALID_TRAIT */ + trait_index = 0; + trait_names[0] = UnityStrInvalidFloatTrait; + break; + } + + if (is_trait != should_be_trait) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrExpected); + if (!should_be_trait) + { + UnityPrint(UnityStrNot); + } + UnityPrint(trait_names[trait_index]); + UnityPrint(UnityStrWas); +#ifndef UNITY_EXCLUDE_FLOAT_PRINT + UnityPrintFloat((UNITY_DOUBLE)actual); +#else + if (should_be_trait) + { + UnityPrint(UnityStrNot); + } + UnityPrint(trait_names[trait_index]); +#endif + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } +} + +#endif /* not UNITY_EXCLUDE_FLOAT */ + +/*-----------------------------------------------*/ +#ifndef UNITY_EXCLUDE_DOUBLE +static int UnityDoublesWithin(UNITY_DOUBLE delta, UNITY_DOUBLE expected, UNITY_DOUBLE actual) +{ + UNITY_DOUBLE diff; + UNITY_FLOAT_OR_DOUBLE_WITHIN(delta, expected, actual, diff); +} + +/*-----------------------------------------------*/ +void UnityAssertEqualDoubleArray(UNITY_PTR_ATTRIBUTE const UNITY_DOUBLE* expected, + UNITY_PTR_ATTRIBUTE const UNITY_DOUBLE* actual, + const UNITY_UINT32 num_elements, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_FLAGS_T flags) +{ + UNITY_UINT32 elements = num_elements; + UNITY_PTR_ATTRIBUTE const UNITY_DOUBLE* ptr_expected = expected; + UNITY_PTR_ATTRIBUTE const UNITY_DOUBLE* ptr_actual = actual; + + RETURN_IF_FAIL_OR_IGNORE; + + if (elements == 0) + { + UnityPrintPointlessAndBail(); + } + + if (expected == actual) + { + return; /* Both are NULL or same pointer */ + } + + if (UnityIsOneArrayNull((UNITY_INTERNAL_PTR)expected, (UNITY_INTERNAL_PTR)actual, lineNumber, msg)) + { + UNITY_FAIL_AND_BAIL; + } + + while (elements--) + { + if (!UnityDoublesWithin(*ptr_expected * UNITY_DOUBLE_PRECISION, *ptr_expected, *ptr_actual)) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrElement); + UnityPrintNumberUnsigned(num_elements - elements - 1); + UNITY_PRINT_EXPECTED_AND_ACTUAL_FLOAT(*ptr_expected, *ptr_actual); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } + if (flags == UNITY_ARRAY_TO_ARRAY) + { + ptr_expected++; + } + ptr_actual++; + } +} + +/*-----------------------------------------------*/ +void UnityAssertDoublesWithin(const UNITY_DOUBLE delta, + const UNITY_DOUBLE expected, + const UNITY_DOUBLE actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber) +{ + RETURN_IF_FAIL_OR_IGNORE; + + if (!UnityDoublesWithin(delta, expected, actual)) + { + UnityTestResultsFailBegin(lineNumber); + UNITY_PRINT_EXPECTED_AND_ACTUAL_FLOAT(expected, actual); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } +} + +/*-----------------------------------------------*/ +void UnityAssertDoubleSpecial(const UNITY_DOUBLE actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_FLOAT_TRAIT_T style) +{ + const char* trait_names[] = {UnityStrInf, UnityStrNegInf, UnityStrNaN, UnityStrDet}; + UNITY_INT should_be_trait = ((UNITY_INT)style & 1); + UNITY_INT is_trait = !should_be_trait; + UNITY_INT trait_index = (UNITY_INT)(style >> 1); + + RETURN_IF_FAIL_OR_IGNORE; + + switch (style) + { + case UNITY_FLOAT_IS_INF: + case UNITY_FLOAT_IS_NOT_INF: + is_trait = isinf(actual) && (actual > 0); + break; + case UNITY_FLOAT_IS_NEG_INF: + case UNITY_FLOAT_IS_NOT_NEG_INF: + is_trait = isinf(actual) && (actual < 0); + break; + + case UNITY_FLOAT_IS_NAN: + case UNITY_FLOAT_IS_NOT_NAN: + is_trait = isnan(actual) ? 1 : 0; + break; + + case UNITY_FLOAT_IS_DET: /* A determinate number is non infinite and not NaN. */ + case UNITY_FLOAT_IS_NOT_DET: + is_trait = !isinf(actual) && !isnan(actual); + break; + + default: /* including UNITY_FLOAT_INVALID_TRAIT */ + trait_index = 0; + trait_names[0] = UnityStrInvalidFloatTrait; + break; + } + + if (is_trait != should_be_trait) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrExpected); + if (!should_be_trait) + { + UnityPrint(UnityStrNot); + } + UnityPrint(trait_names[trait_index]); + UnityPrint(UnityStrWas); +#ifndef UNITY_EXCLUDE_FLOAT_PRINT + UnityPrintFloat(actual); +#else + if (should_be_trait) + { + UnityPrint(UnityStrNot); + } + UnityPrint(trait_names[trait_index]); +#endif + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } +} + +#endif /* not UNITY_EXCLUDE_DOUBLE */ + +/*-----------------------------------------------*/ +void UnityAssertNumbersWithin(const UNITY_UINT delta, + const UNITY_INT expected, + const UNITY_INT actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_DISPLAY_STYLE_T style) +{ + RETURN_IF_FAIL_OR_IGNORE; + + if ((style & UNITY_DISPLAY_RANGE_INT) == UNITY_DISPLAY_RANGE_INT) + { + if (actual > expected) + { + Unity.CurrentTestFailed = (((UNITY_UINT)actual - (UNITY_UINT)expected) > delta); + } + else + { + Unity.CurrentTestFailed = (((UNITY_UINT)expected - (UNITY_UINT)actual) > delta); + } + } + else + { + if ((UNITY_UINT)actual > (UNITY_UINT)expected) + { + Unity.CurrentTestFailed = (((UNITY_UINT)actual - (UNITY_UINT)expected) > delta); + } + else + { + Unity.CurrentTestFailed = (((UNITY_UINT)expected - (UNITY_UINT)actual) > delta); + } + } + + if (Unity.CurrentTestFailed) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrDelta); + UnityPrintNumberByStyle((UNITY_INT)delta, style); + UnityPrint(UnityStrExpected); + UnityPrintNumberByStyle(expected, style); + UnityPrint(UnityStrWas); + UnityPrintNumberByStyle(actual, style); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } +} + +/*-----------------------------------------------*/ +void UnityAssertNumbersArrayWithin(const UNITY_UINT delta, + UNITY_INTERNAL_PTR expected, + UNITY_INTERNAL_PTR actual, + const UNITY_UINT32 num_elements, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_DISPLAY_STYLE_T style, + const UNITY_FLAGS_T flags) +{ + UNITY_UINT32 elements = num_elements; + unsigned int length = style & 0xF; + unsigned int increment = 0; + + RETURN_IF_FAIL_OR_IGNORE; + + if (num_elements == 0) + { + UnityPrintPointlessAndBail(); + } + + if (expected == actual) + { + return; /* Both are NULL or same pointer */ + } + + if (UnityIsOneArrayNull(expected, actual, lineNumber, msg)) + { + UNITY_FAIL_AND_BAIL; + } + + while ((elements > 0) && (elements--)) + { + UNITY_INT expect_val; + UNITY_INT actual_val; + + switch (length) + { + case 1: + expect_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT8*)expected; + actual_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT8*)actual; + increment = sizeof(UNITY_INT8); + break; + + case 2: + expect_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT16*)expected; + actual_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT16*)actual; + increment = sizeof(UNITY_INT16); + break; + +#ifdef UNITY_SUPPORT_64 + case 8: + expect_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT64*)expected; + actual_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT64*)actual; + increment = sizeof(UNITY_INT64); + break; +#endif + + default: /* default is length 4 bytes */ + case 4: + expect_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT32*)expected; + actual_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT32*)actual; + increment = sizeof(UNITY_INT32); + length = 4; + break; + } + + if ((style & UNITY_DISPLAY_RANGE_INT) == UNITY_DISPLAY_RANGE_INT) + { + if (actual_val > expect_val) + { + Unity.CurrentTestFailed = (((UNITY_UINT)actual_val - (UNITY_UINT)expect_val) > delta); + } + else + { + Unity.CurrentTestFailed = (((UNITY_UINT)expect_val - (UNITY_UINT)actual_val) > delta); + } + } + else + { + if ((UNITY_UINT)actual_val > (UNITY_UINT)expect_val) + { + Unity.CurrentTestFailed = (((UNITY_UINT)actual_val - (UNITY_UINT)expect_val) > delta); + } + else + { + Unity.CurrentTestFailed = (((UNITY_UINT)expect_val - (UNITY_UINT)actual_val) > delta); + } + } + + if (Unity.CurrentTestFailed) + { + if ((style & UNITY_DISPLAY_RANGE_UINT) && (length < (UNITY_INT_WIDTH / 8))) + { /* For UINT, remove sign extension (padding 1's) from signed type casts above */ + UNITY_INT mask = 1; + mask = (mask << 8 * length) - 1; + expect_val &= mask; + actual_val &= mask; + } + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrDelta); + UnityPrintNumberByStyle((UNITY_INT)delta, style); + UnityPrint(UnityStrElement); + UnityPrintNumberUnsigned(num_elements - elements - 1); + UnityPrint(UnityStrExpected); + UnityPrintNumberByStyle(expect_val, style); + UnityPrint(UnityStrWas); + UnityPrintNumberByStyle(actual_val, style); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } + /* Walk through array by incrementing the pointers */ + if (flags == UNITY_ARRAY_TO_ARRAY) + { + expected = (UNITY_INTERNAL_PTR)((const char*)expected + increment); + } + actual = (UNITY_INTERNAL_PTR)((const char*)actual + increment); + } +} + +/*-----------------------------------------------*/ +void UnityAssertEqualString(const char* expected, + const char* actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber) +{ + UNITY_UINT32 i; + + RETURN_IF_FAIL_OR_IGNORE; + + /* if both pointers not null compare the strings */ + if (expected && actual) + { + for (i = 0; expected[i] || actual[i]; i++) + { + if (expected[i] != actual[i]) + { + Unity.CurrentTestFailed = 1; + break; + } + } + } + else + { /* handle case of one pointers being null (if both null, test should pass) */ + if (expected != actual) + { + Unity.CurrentTestFailed = 1; + } + } + + if (Unity.CurrentTestFailed) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrintExpectedAndActualStrings(expected, actual); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } +} + +/*-----------------------------------------------*/ +void UnityAssertEqualStringLen(const char* expected, + const char* actual, + const UNITY_UINT32 length, + const char* msg, + const UNITY_LINE_TYPE lineNumber) +{ + UNITY_UINT32 i; + + RETURN_IF_FAIL_OR_IGNORE; + + /* if both pointers not null compare the strings */ + if (expected && actual) + { + for (i = 0; (i < length) && (expected[i] || actual[i]); i++) + { + if (expected[i] != actual[i]) + { + Unity.CurrentTestFailed = 1; + break; + } + } + } + else + { /* handle case of one pointers being null (if both null, test should pass) */ + if (expected != actual) + { + Unity.CurrentTestFailed = 1; + } + } + + if (Unity.CurrentTestFailed) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrintExpectedAndActualStringsLen(expected, actual, length); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } +} + +/*-----------------------------------------------*/ +void UnityAssertEqualStringArray(UNITY_INTERNAL_PTR expected, + const char** actual, + const UNITY_UINT32 num_elements, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_FLAGS_T flags) +{ + UNITY_UINT32 i = 0; + UNITY_UINT32 j = 0; + const char* expd = NULL; + const char* act = NULL; + + RETURN_IF_FAIL_OR_IGNORE; + + /* if no elements, it's an error */ + if (num_elements == 0) + { + UnityPrintPointlessAndBail(); + } + + if ((const void*)expected == (const void*)actual) + { + return; /* Both are NULL or same pointer */ + } + + if (UnityIsOneArrayNull((UNITY_INTERNAL_PTR)expected, (UNITY_INTERNAL_PTR)actual, lineNumber, msg)) + { + UNITY_FAIL_AND_BAIL; + } + + if (flags != UNITY_ARRAY_TO_ARRAY) + { + expd = (const char*)expected; + } + + do + { + act = actual[j]; + if (flags == UNITY_ARRAY_TO_ARRAY) + { + expd = ((const char* const*)expected)[j]; + } + + /* if both pointers not null compare the strings */ + if (expd && act) + { + for (i = 0; expd[i] || act[i]; i++) + { + if (expd[i] != act[i]) + { + Unity.CurrentTestFailed = 1; + break; + } + } + } + else + { /* handle case of one pointers being null (if both null, test should pass) */ + if (expd != act) + { + Unity.CurrentTestFailed = 1; + } + } + + if (Unity.CurrentTestFailed) + { + UnityTestResultsFailBegin(lineNumber); + if (num_elements > 1) + { + UnityPrint(UnityStrElement); + UnityPrintNumberUnsigned(j); + } + UnityPrintExpectedAndActualStrings(expd, act); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } + } while (++j < num_elements); +} + +/*-----------------------------------------------*/ +void UnityAssertEqualMemory(UNITY_INTERNAL_PTR expected, + UNITY_INTERNAL_PTR actual, + const UNITY_UINT32 length, + const UNITY_UINT32 num_elements, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_FLAGS_T flags) +{ + UNITY_PTR_ATTRIBUTE const unsigned char* ptr_exp = (UNITY_PTR_ATTRIBUTE const unsigned char*)expected; + UNITY_PTR_ATTRIBUTE const unsigned char* ptr_act = (UNITY_PTR_ATTRIBUTE const unsigned char*)actual; + UNITY_UINT32 elements = num_elements; + UNITY_UINT32 bytes; + + RETURN_IF_FAIL_OR_IGNORE; + + if ((elements == 0) || (length == 0)) + { + UnityPrintPointlessAndBail(); + } + + if (expected == actual) + { + return; /* Both are NULL or same pointer */ + } + + if (UnityIsOneArrayNull(expected, actual, lineNumber, msg)) + { + UNITY_FAIL_AND_BAIL; + } + + while (elements--) + { + bytes = length; + while (bytes--) + { + if (*ptr_exp != *ptr_act) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrMemory); + if (num_elements > 1) + { + UnityPrint(UnityStrElement); + UnityPrintNumberUnsigned(num_elements - elements - 1); + } + UnityPrint(UnityStrByte); + UnityPrintNumberUnsigned(length - bytes - 1); + UnityPrint(UnityStrExpected); + UnityPrintNumberByStyle(*ptr_exp, UNITY_DISPLAY_STYLE_HEX8); + UnityPrint(UnityStrWas); + UnityPrintNumberByStyle(*ptr_act, UNITY_DISPLAY_STYLE_HEX8); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } + ptr_exp++; + ptr_act++; + } + if (flags == UNITY_ARRAY_TO_VAL) + { + ptr_exp = (UNITY_PTR_ATTRIBUTE const unsigned char*)expected; + } + } +} + +/*-----------------------------------------------*/ + +static union +{ + UNITY_INT8 i8; + UNITY_INT16 i16; + UNITY_INT32 i32; +#ifdef UNITY_SUPPORT_64 + UNITY_INT64 i64; +#endif +#ifndef UNITY_EXCLUDE_FLOAT + float f; +#endif +#ifndef UNITY_EXCLUDE_DOUBLE + double d; +#endif +} UnityQuickCompare; + +UNITY_INTERNAL_PTR UnityNumToPtr(const UNITY_INT num, const UNITY_UINT8 size) +{ + switch(size) + { + case 1: + UnityQuickCompare.i8 = (UNITY_INT8)num; + return (UNITY_INTERNAL_PTR)(&UnityQuickCompare.i8); + + case 2: + UnityQuickCompare.i16 = (UNITY_INT16)num; + return (UNITY_INTERNAL_PTR)(&UnityQuickCompare.i16); + +#ifdef UNITY_SUPPORT_64 + case 8: + UnityQuickCompare.i64 = (UNITY_INT64)num; + return (UNITY_INTERNAL_PTR)(&UnityQuickCompare.i64); +#endif + + default: /* 4 bytes */ + UnityQuickCompare.i32 = (UNITY_INT32)num; + return (UNITY_INTERNAL_PTR)(&UnityQuickCompare.i32); + } +} + +#ifndef UNITY_EXCLUDE_FLOAT +/*-----------------------------------------------*/ +UNITY_INTERNAL_PTR UnityFloatToPtr(const float num) +{ + UnityQuickCompare.f = num; + return (UNITY_INTERNAL_PTR)(&UnityQuickCompare.f); +} +#endif + +#ifndef UNITY_EXCLUDE_DOUBLE +/*-----------------------------------------------*/ +UNITY_INTERNAL_PTR UnityDoubleToPtr(const double num) +{ + UnityQuickCompare.d = num; + return (UNITY_INTERNAL_PTR)(&UnityQuickCompare.d); +} +#endif + +/*----------------------------------------------- + * printf helper function + *-----------------------------------------------*/ +#ifdef UNITY_INCLUDE_PRINT_FORMATTED +static void UnityPrintFVA(const char* format, va_list va) +{ + const char* pch = format; + if (pch != NULL) + { + while (*pch) + { + /* format identification character */ + if (*pch == '%') + { + pch++; + + if (pch != NULL) + { + switch (*pch) + { + case 'd': + case 'i': + { + const int number = va_arg(va, int); + UnityPrintNumber((UNITY_INT)number); + break; + } +#ifndef UNITY_EXCLUDE_FLOAT_PRINT + case 'f': + case 'g': + { + const double number = va_arg(va, double); + UnityPrintFloat((UNITY_DOUBLE)number); + break; + } +#endif + case 'u': + { + const unsigned int number = va_arg(va, unsigned int); + UnityPrintNumberUnsigned((UNITY_UINT)number); + break; + } + case 'b': + { + const unsigned int number = va_arg(va, unsigned int); + const UNITY_UINT mask = (UNITY_UINT)0 - (UNITY_UINT)1; + UNITY_OUTPUT_CHAR('0'); + UNITY_OUTPUT_CHAR('b'); + UnityPrintMask(mask, (UNITY_UINT)number); + break; + } + case 'x': + case 'X': + case 'p': + { + const unsigned int number = va_arg(va, unsigned int); + UNITY_OUTPUT_CHAR('0'); + UNITY_OUTPUT_CHAR('x'); + UnityPrintNumberHex((UNITY_UINT)number, 8); + break; + } + case 'c': + { + const int ch = va_arg(va, int); + UnityPrintChar((const char *)&ch); + break; + } + case 's': + { + const char * string = va_arg(va, const char *); + UnityPrint(string); + break; + } + case '%': + { + UnityPrintChar(pch); + break; + } + default: + { + /* print the unknown format character */ + UNITY_OUTPUT_CHAR('%'); + UnityPrintChar(pch); + break; + } + } + } + } +#ifdef UNITY_OUTPUT_COLOR + /* print ANSI escape code */ + else if ((*pch == 27) && (*(pch + 1) == '[')) + { + pch += UnityPrintAnsiEscapeString(pch); + continue; + } +#endif + else if (*pch == '\n') + { + UNITY_PRINT_EOL(); + } + else + { + UnityPrintChar(pch); + } + + pch++; + } + } +} + +void UnityPrintF(const UNITY_LINE_TYPE line, const char* format, ...) +{ + UnityTestResultsBegin(Unity.TestFile, line); + UnityPrint("INFO"); + if(format != NULL) + { + UnityPrint(": "); + va_list va; + va_start(va, format); + UnityPrintFVA(format, va); + va_end(va); + } + UNITY_PRINT_EOL(); +} +#endif /* ! UNITY_INCLUDE_PRINT_FORMATTED */ + + +/*----------------------------------------------- + * Control Functions + *-----------------------------------------------*/ + +/*-----------------------------------------------*/ +void UnityFail(const char* msg, const UNITY_LINE_TYPE line) +{ + RETURN_IF_FAIL_OR_IGNORE; + + UnityTestResultsBegin(Unity.TestFile, line); + UnityPrint(UnityStrFail); + if (msg != NULL) + { + UNITY_OUTPUT_CHAR(':'); + +#ifdef UNITY_PRINT_TEST_CONTEXT + UNITY_PRINT_TEST_CONTEXT(); +#endif +#ifndef UNITY_EXCLUDE_DETAILS + if (Unity.CurrentDetail1) + { + UnityPrint(UnityStrDetail1Name); + UnityPrint(Unity.CurrentDetail1); + if (Unity.CurrentDetail2) + { + UnityPrint(UnityStrDetail2Name); + UnityPrint(Unity.CurrentDetail2); + } + UnityPrint(UnityStrSpacer); + } +#endif + if (msg[0] != ' ') + { + UNITY_OUTPUT_CHAR(' '); + } + UnityPrint(msg); + } + + UNITY_FAIL_AND_BAIL; +} + +/*-----------------------------------------------*/ +void UnityIgnore(const char* msg, const UNITY_LINE_TYPE line) +{ + RETURN_IF_FAIL_OR_IGNORE; + + UnityTestResultsBegin(Unity.TestFile, line); + UnityPrint(UnityStrIgnore); + if (msg != NULL) + { + UNITY_OUTPUT_CHAR(':'); + UNITY_OUTPUT_CHAR(' '); + UnityPrint(msg); + } + UNITY_IGNORE_AND_BAIL; +} + +/*-----------------------------------------------*/ +void UnityMessage(const char* msg, const UNITY_LINE_TYPE line) +{ + UnityTestResultsBegin(Unity.TestFile, line); + UnityPrint("INFO"); + if (msg != NULL) + { + UNITY_OUTPUT_CHAR(':'); + UNITY_OUTPUT_CHAR(' '); + UnityPrint(msg); + } + UNITY_PRINT_EOL(); +} + +/*-----------------------------------------------*/ +/* If we have not defined our own test runner, then include our default test runner to make life easier */ +#ifndef UNITY_SKIP_DEFAULT_RUNNER +void UnityDefaultTestRun(UnityTestFunction Func, const char* FuncName, const int FuncLineNum) +{ + Unity.CurrentTestName = FuncName; + Unity.CurrentTestLineNumber = (UNITY_LINE_TYPE)FuncLineNum; + Unity.NumberOfTests++; + UNITY_CLR_DETAILS(); + UNITY_EXEC_TIME_START(); + if (TEST_PROTECT()) + { + setUp(); + Func(); + } + if (TEST_PROTECT()) + { + tearDown(); + } + UNITY_EXEC_TIME_STOP(); + UnityConcludeTest(); +} +#endif + +/*-----------------------------------------------*/ +void UnitySetTestFile(const char* filename) +{ + Unity.TestFile = filename; +} + +/*-----------------------------------------------*/ +void UnityBegin(const char* filename) +{ + Unity.TestFile = filename; + Unity.CurrentTestName = NULL; + Unity.CurrentTestLineNumber = 0; + Unity.NumberOfTests = 0; + Unity.TestFailures = 0; + Unity.TestIgnores = 0; + Unity.CurrentTestFailed = 0; + Unity.CurrentTestIgnored = 0; + + UNITY_CLR_DETAILS(); + UNITY_OUTPUT_START(); +} + +/*-----------------------------------------------*/ +int UnityEnd(void) +{ + UNITY_PRINT_EOL(); + UnityPrint(UnityStrBreaker); + UNITY_PRINT_EOL(); + UnityPrintNumber((UNITY_INT)(Unity.NumberOfTests)); + UnityPrint(UnityStrResultsTests); + UnityPrintNumber((UNITY_INT)(Unity.TestFailures)); + UnityPrint(UnityStrResultsFailures); + UnityPrintNumber((UNITY_INT)(Unity.TestIgnores)); + UnityPrint(UnityStrResultsIgnored); + UNITY_PRINT_EOL(); + if (Unity.TestFailures == 0U) + { + UnityPrint(UnityStrOk); + } + else + { + UnityPrint(UnityStrFail); +#ifdef UNITY_DIFFERENTIATE_FINAL_FAIL + UNITY_OUTPUT_CHAR('E'); UNITY_OUTPUT_CHAR('D'); +#endif + } + UNITY_PRINT_EOL(); + UNITY_FLUSH_CALL(); + UNITY_OUTPUT_COMPLETE(); + return (int)(Unity.TestFailures); +} + +/*----------------------------------------------- + * Command Line Argument Support + *-----------------------------------------------*/ +#ifdef UNITY_USE_COMMAND_LINE_ARGS + +char* UnityOptionIncludeNamed = NULL; +char* UnityOptionExcludeNamed = NULL; +int UnityVerbosity = 1; + +/*-----------------------------------------------*/ +int UnityParseOptions(int argc, char** argv) +{ + int i; + UnityOptionIncludeNamed = NULL; + UnityOptionExcludeNamed = NULL; + + for (i = 1; i < argc; i++) + { + if (argv[i][0] == '-') + { + switch (argv[i][1]) + { + case 'l': /* list tests */ + return -1; + case 'n': /* include tests with name including this string */ + case 'f': /* an alias for -n */ + if (argv[i][2] == '=') + { + UnityOptionIncludeNamed = &argv[i][3]; + } + else if (++i < argc) + { + UnityOptionIncludeNamed = argv[i]; + } + else + { + UnityPrint("ERROR: No Test String to Include Matches For"); + UNITY_PRINT_EOL(); + return 1; + } + break; + case 'q': /* quiet */ + UnityVerbosity = 0; + break; + case 'v': /* verbose */ + UnityVerbosity = 2; + break; + case 'x': /* exclude tests with name including this string */ + if (argv[i][2] == '=') + { + UnityOptionExcludeNamed = &argv[i][3]; + } + else if (++i < argc) + { + UnityOptionExcludeNamed = argv[i]; + } + else + { + UnityPrint("ERROR: No Test String to Exclude Matches For"); + UNITY_PRINT_EOL(); + return 1; + } + break; + default: + UnityPrint("ERROR: Unknown Option "); + UNITY_OUTPUT_CHAR(argv[i][1]); + UNITY_PRINT_EOL(); + return 1; + } + } + } + + return 0; +} + +/*-----------------------------------------------*/ +int IsStringInBiggerString(const char* longstring, const char* shortstring) +{ + const char* lptr = longstring; + const char* sptr = shortstring; + const char* lnext = lptr; + + if (*sptr == '*') + { + return 1; + } + + while (*lptr) + { + lnext = lptr + 1; + + /* If they current bytes match, go on to the next bytes */ + while (*lptr && *sptr && (*lptr == *sptr)) + { + lptr++; + sptr++; + + /* We're done if we match the entire string or up to a wildcard */ + if (*sptr == '*') + return 1; + if (*sptr == ',') + return 1; + if (*sptr == '"') + return 1; + if (*sptr == '\'') + return 1; + if (*sptr == ':') + return 2; + if (*sptr == 0) + return 1; + } + + /* Otherwise we start in the long pointer 1 character further and try again */ + lptr = lnext; + sptr = shortstring; + } + + return 0; +} + +/*-----------------------------------------------*/ +int UnityStringArgumentMatches(const char* str) +{ + int retval; + const char* ptr1; + const char* ptr2; + const char* ptrf; + + /* Go through the options and get the substrings for matching one at a time */ + ptr1 = str; + while (ptr1[0] != 0) + { + if ((ptr1[0] == '"') || (ptr1[0] == '\'')) + { + ptr1++; + } + + /* look for the start of the next partial */ + ptr2 = ptr1; + ptrf = 0; + do + { + ptr2++; + if ((ptr2[0] == ':') && (ptr2[1] != 0) && (ptr2[0] != '\'') && (ptr2[0] != '"') && (ptr2[0] != ',')) + { + ptrf = &ptr2[1]; + } + } while ((ptr2[0] != 0) && (ptr2[0] != '\'') && (ptr2[0] != '"') && (ptr2[0] != ',')); + + while ((ptr2[0] != 0) && ((ptr2[0] == ':') || (ptr2[0] == '\'') || (ptr2[0] == '"') || (ptr2[0] == ','))) + { + ptr2++; + } + + /* done if complete filename match */ + retval = IsStringInBiggerString(Unity.TestFile, ptr1); + if (retval == 1) + { + return retval; + } + + /* done if testname match after filename partial match */ + if ((retval == 2) && (ptrf != 0)) + { + if (IsStringInBiggerString(Unity.CurrentTestName, ptrf)) + { + return 1; + } + } + + /* done if complete testname match */ + if (IsStringInBiggerString(Unity.CurrentTestName, ptr1) == 1) + { + return 1; + } + + ptr1 = ptr2; + } + + /* we couldn't find a match for any substrings */ + return 0; +} + +/*-----------------------------------------------*/ +int UnityTestMatches(void) +{ + /* Check if this test name matches the included test pattern */ + int retval; + if (UnityOptionIncludeNamed) + { + retval = UnityStringArgumentMatches(UnityOptionIncludeNamed); + } + else + { + retval = 1; + } + + /* Check if this test name matches the excluded test pattern */ + if (UnityOptionExcludeNamed) + { + if (UnityStringArgumentMatches(UnityOptionExcludeNamed)) + { + retval = 0; + } + } + + return retval; +} + +#endif /* UNITY_USE_COMMAND_LINE_ARGS */ +/*-----------------------------------------------*/ diff --git a/c/hello-world/test-framework/unity.h b/c/hello-world/test-framework/unity.h new file mode 100644 index 0000000..ab986c4 --- /dev/null +++ b/c/hello-world/test-framework/unity.h @@ -0,0 +1,661 @@ +/* ========================================== + Unity Project - A Test Framework for C + Copyright (c) 2007-21 Mike Karlesky, Mark VanderVoord, Greg Williams + [Released under MIT License. Please refer to license.txt for details] +========================================== */ + +#ifndef UNITY_FRAMEWORK_H +#define UNITY_FRAMEWORK_H +#define UNITY + +#define UNITY_VERSION_MAJOR 2 +#define UNITY_VERSION_MINOR 5 +#define UNITY_VERSION_BUILD 2 +#define UNITY_VERSION ((UNITY_VERSION_MAJOR << 16) | (UNITY_VERSION_MINOR << 8) | UNITY_VERSION_BUILD) + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "unity_internals.h" + +/*------------------------------------------------------- + * Test Setup / Teardown + *-------------------------------------------------------*/ + +/* These functions are intended to be called before and after each test. + * If using unity directly, these will need to be provided for each test + * executable built. If you are using the test runner generator and/or + * Ceedling, these are optional. */ +void setUp(void); +void tearDown(void); + +/* These functions are intended to be called at the beginning and end of an + * entire test suite. suiteTearDown() is passed the number of tests that + * failed, and its return value becomes the exit code of main(). If using + * Unity directly, you're in charge of calling these if they are desired. + * If using Ceedling or the test runner generator, these will be called + * automatically if they exist. */ +void suiteSetUp(void); +int suiteTearDown(int num_failures); + +/*------------------------------------------------------- + * Test Reset and Verify + *-------------------------------------------------------*/ + +/* These functions are intended to be called before during tests in order + * to support complex test loops, etc. Both are NOT built into Unity. Instead + * the test runner generator will create them. resetTest will run teardown and + * setup again, verifying any end-of-test needs between. verifyTest will only + * run the verification. */ +void resetTest(void); +void verifyTest(void); + +/*------------------------------------------------------- + * Configuration Options + *------------------------------------------------------- + * All options described below should be passed as a compiler flag to all files using Unity. If you must add #defines, place them BEFORE the #include above. + + * Integers/longs/pointers + * - Unity attempts to automatically discover your integer sizes + * - define UNITY_EXCLUDE_STDINT_H to stop attempting to look in + * - define UNITY_EXCLUDE_LIMITS_H to stop attempting to look in + * - If you cannot use the automatic methods above, you can force Unity by using these options: + * - define UNITY_SUPPORT_64 + * - set UNITY_INT_WIDTH + * - set UNITY_LONG_WIDTH + * - set UNITY_POINTER_WIDTH + + * Floats + * - define UNITY_EXCLUDE_FLOAT to disallow floating point comparisons + * - define UNITY_FLOAT_PRECISION to specify the precision to use when doing TEST_ASSERT_EQUAL_FLOAT + * - define UNITY_FLOAT_TYPE to specify doubles instead of single precision floats + * - define UNITY_INCLUDE_DOUBLE to allow double floating point comparisons + * - define UNITY_EXCLUDE_DOUBLE to disallow double floating point comparisons (default) + * - define UNITY_DOUBLE_PRECISION to specify the precision to use when doing TEST_ASSERT_EQUAL_DOUBLE + * - define UNITY_DOUBLE_TYPE to specify something other than double + * - define UNITY_EXCLUDE_FLOAT_PRINT to trim binary size, won't print floating point values in errors + + * Output + * - by default, Unity prints to standard out with putchar. define UNITY_OUTPUT_CHAR(a) with a different function if desired + * - define UNITY_DIFFERENTIATE_FINAL_FAIL to print FAILED (vs. FAIL) at test end summary - for automated search for failure + + * Optimization + * - by default, line numbers are stored in unsigned shorts. Define UNITY_LINE_TYPE with a different type if your files are huge + * - by default, test and failure counters are unsigned shorts. Define UNITY_COUNTER_TYPE with a different type if you want to save space or have more than 65535 Tests. + + * Test Cases + * - define UNITY_SUPPORT_TEST_CASES to include the TEST_CASE macro, though really it's mostly about the runner generator script + + * Parameterized Tests + * - you'll want to create a define of TEST_CASE(...) which basically evaluates to nothing + + * Tests with Arguments + * - you'll want to define UNITY_USE_COMMAND_LINE_ARGS if you have the test runner passing arguments to Unity + + *------------------------------------------------------- + * Basic Fail and Ignore + *-------------------------------------------------------*/ + +#define TEST_FAIL_MESSAGE(message) UNITY_TEST_FAIL(__LINE__, (message)) +#define TEST_FAIL() UNITY_TEST_FAIL(__LINE__, NULL) +#define TEST_IGNORE_MESSAGE(message) UNITY_TEST_IGNORE(__LINE__, (message)) +#define TEST_IGNORE() UNITY_TEST_IGNORE(__LINE__, NULL) +#define TEST_MESSAGE(message) UnityMessage((message), __LINE__) +#define TEST_ONLY() +#ifdef UNITY_INCLUDE_PRINT_FORMATTED +#define TEST_PRINTF(message, ...) UnityPrintF(__LINE__, (message), __VA_ARGS__) +#endif + +/* It is not necessary for you to call PASS. A PASS condition is assumed if nothing fails. + * This method allows you to abort a test immediately with a PASS state, ignoring the remainder of the test. */ +#define TEST_PASS() TEST_ABORT() +#define TEST_PASS_MESSAGE(message) do { UnityMessage((message), __LINE__); TEST_ABORT(); } while(0) + +/* This macro does nothing, but it is useful for build tools (like Ceedling) to make use of this to figure out + * which files should be linked to in order to perform a test. Use it like TEST_FILE("sandwiches.c") */ +#define TEST_FILE(a) + +/*------------------------------------------------------- + * Test Asserts (simple) + *-------------------------------------------------------*/ + +/* Boolean */ +#define TEST_ASSERT(condition) UNITY_TEST_ASSERT( (condition), __LINE__, " Expression Evaluated To FALSE") +#define TEST_ASSERT_TRUE(condition) UNITY_TEST_ASSERT( (condition), __LINE__, " Expected TRUE Was FALSE") +#define TEST_ASSERT_UNLESS(condition) UNITY_TEST_ASSERT( !(condition), __LINE__, " Expression Evaluated To TRUE") +#define TEST_ASSERT_FALSE(condition) UNITY_TEST_ASSERT( !(condition), __LINE__, " Expected FALSE Was TRUE") +#define TEST_ASSERT_NULL(pointer) UNITY_TEST_ASSERT_NULL( (pointer), __LINE__, " Expected NULL") +#define TEST_ASSERT_NOT_NULL(pointer) UNITY_TEST_ASSERT_NOT_NULL((pointer), __LINE__, " Expected Non-NULL") +#define TEST_ASSERT_EMPTY(pointer) UNITY_TEST_ASSERT_EMPTY( (pointer), __LINE__, " Expected Empty") +#define TEST_ASSERT_NOT_EMPTY(pointer) UNITY_TEST_ASSERT_NOT_EMPTY((pointer), __LINE__, " Expected Non-Empty") + +/* Integers (of all sizes) */ +#define TEST_ASSERT_EQUAL_INT(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_INT8(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT8((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_INT16(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT16((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_INT32(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT32((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_INT64(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT64((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_UINT(expected, actual) UNITY_TEST_ASSERT_EQUAL_UINT( (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_UINT8(expected, actual) UNITY_TEST_ASSERT_EQUAL_UINT8( (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_UINT16(expected, actual) UNITY_TEST_ASSERT_EQUAL_UINT16( (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_UINT32(expected, actual) UNITY_TEST_ASSERT_EQUAL_UINT32( (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_UINT64(expected, actual) UNITY_TEST_ASSERT_EQUAL_UINT64( (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_size_t(expected, actual) UNITY_TEST_ASSERT_EQUAL_UINT((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_HEX(expected, actual) UNITY_TEST_ASSERT_EQUAL_HEX32((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_HEX8(expected, actual) UNITY_TEST_ASSERT_EQUAL_HEX8( (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_HEX16(expected, actual) UNITY_TEST_ASSERT_EQUAL_HEX16((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_HEX32(expected, actual) UNITY_TEST_ASSERT_EQUAL_HEX32((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_HEX64(expected, actual) UNITY_TEST_ASSERT_EQUAL_HEX64((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_CHAR(expected, actual) UNITY_TEST_ASSERT_EQUAL_CHAR((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_BITS(mask, expected, actual) UNITY_TEST_ASSERT_BITS((mask), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_BITS_HIGH(mask, actual) UNITY_TEST_ASSERT_BITS((mask), (UNITY_UINT)(-1), (actual), __LINE__, NULL) +#define TEST_ASSERT_BITS_LOW(mask, actual) UNITY_TEST_ASSERT_BITS((mask), (UNITY_UINT)(0), (actual), __LINE__, NULL) +#define TEST_ASSERT_BIT_HIGH(bit, actual) UNITY_TEST_ASSERT_BITS(((UNITY_UINT)1 << (bit)), (UNITY_UINT)(-1), (actual), __LINE__, NULL) +#define TEST_ASSERT_BIT_LOW(bit, actual) UNITY_TEST_ASSERT_BITS(((UNITY_UINT)1 << (bit)), (UNITY_UINT)(0), (actual), __LINE__, NULL) + +/* Integer Not Equal To (of all sizes) */ +#define TEST_ASSERT_NOT_EQUAL_INT(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_INT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_INT8(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_INT8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_INT16(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_INT16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_INT32(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_INT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_INT64(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_INT64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_UINT(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_UINT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_UINT8(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_UINT8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_UINT16(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_UINT16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_UINT32(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_UINT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_UINT64(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_UINT64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_size_t(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_UINT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_HEX8(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_HEX8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_HEX16(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_HEX16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_HEX32(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_HEX32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_HEX64(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_HEX64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_CHAR(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_CHAR((threshold), (actual), __LINE__, NULL) + +/* Integer Greater Than/ Less Than (of all sizes) */ +#define TEST_ASSERT_GREATER_THAN(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_INT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_INT(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_INT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_INT8(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_INT8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_INT16(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_INT16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_INT32(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_INT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_INT64(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_INT64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_UINT(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_UINT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_UINT8(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_UINT8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_UINT16(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_UINT16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_UINT32(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_UINT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_UINT64(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_UINT64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_size_t(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_UINT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_HEX8(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_HEX8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_HEX16(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_HEX16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_HEX32(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_HEX32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_HEX64(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_HEX64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_CHAR(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_CHAR((threshold), (actual), __LINE__, NULL) + +#define TEST_ASSERT_LESS_THAN(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_INT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_INT(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_INT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_INT8(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_INT8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_INT16(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_INT16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_INT32(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_INT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_INT64(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_INT64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_UINT(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_UINT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_UINT8(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_UINT8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_UINT16(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_UINT16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_UINT32(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_UINT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_UINT64(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_UINT64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_size_t(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_UINT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_HEX8(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_HEX8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_HEX16(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_HEX16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_HEX32(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_HEX32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_HEX64(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_HEX64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_CHAR(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_CHAR((threshold), (actual), __LINE__, NULL) + +#define TEST_ASSERT_GREATER_OR_EQUAL(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT8(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT16(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT32(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT64(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT8(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT16(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT32(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT64(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_size_t(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_HEX8(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_HEX16(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_HEX32(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_HEX64(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_CHAR(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_CHAR((threshold), (actual), __LINE__, NULL) + +#define TEST_ASSERT_LESS_OR_EQUAL(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_INT(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_INT8(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_INT16(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_INT32(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_INT64(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT8(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT16(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT32(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT64(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_size_t(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_HEX8(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_HEX16(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_HEX32(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_HEX64(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_CHAR(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_CHAR((threshold), (actual), __LINE__, NULL) + +/* Integer Ranges (of all sizes) */ +#define TEST_ASSERT_INT_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_INT_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_INT8_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_INT8_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_INT16_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_INT16_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_INT32_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_INT32_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_INT64_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_INT64_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_UINT_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_UINT_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_UINT8_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_UINT8_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_UINT16_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_UINT16_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_UINT32_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_UINT32_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_UINT64_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_UINT64_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_size_t_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_UINT_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_HEX_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_HEX32_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_HEX8_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_HEX8_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_HEX16_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_HEX16_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_HEX32_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_HEX32_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_HEX64_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_HEX64_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_CHAR_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_CHAR_WITHIN((delta), (expected), (actual), __LINE__, NULL) + +/* Integer Array Ranges (of all sizes) */ +#define TEST_ASSERT_INT_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_INT_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_INT8_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_INT8_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_INT16_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_INT16_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_INT32_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_INT32_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_INT64_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_INT64_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_UINT_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_UINT_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_UINT8_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_UINT8_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_UINT16_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_UINT16_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_UINT32_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_UINT32_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_UINT64_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_UINT64_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_size_t_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_UINT_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_HEX_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_HEX32_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_HEX8_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_HEX8_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_HEX16_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_HEX16_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_HEX32_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_HEX32_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_HEX64_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_HEX64_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_CHAR_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_CHAR_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) + + +/* Structs and Strings */ +#define TEST_ASSERT_EQUAL_PTR(expected, actual) UNITY_TEST_ASSERT_EQUAL_PTR((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_STRING(expected, actual) UNITY_TEST_ASSERT_EQUAL_STRING((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_STRING_LEN(expected, actual, len) UNITY_TEST_ASSERT_EQUAL_STRING_LEN((expected), (actual), (len), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_MEMORY(expected, actual, len) UNITY_TEST_ASSERT_EQUAL_MEMORY((expected), (actual), (len), __LINE__, NULL) + +/* Arrays */ +#define TEST_ASSERT_EQUAL_INT_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_INT_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_INT8_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_INT8_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_INT16_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_INT16_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_INT32_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_INT32_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_INT64_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_INT64_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_UINT_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_UINT_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_UINT8_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_UINT8_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_UINT16_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_UINT16_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_UINT32_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_UINT32_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_UINT64_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_UINT64_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_size_t_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_UINT_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_HEX_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_HEX32_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_HEX8_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_HEX8_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_HEX16_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_HEX16_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_HEX32_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_HEX32_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_HEX64_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_HEX64_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_PTR_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_PTR_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_STRING_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_STRING_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_MEMORY_ARRAY(expected, actual, len, num_elements) UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY((expected), (actual), (len), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_CHAR_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_CHAR_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) + +/* Arrays Compared To Single Value */ +#define TEST_ASSERT_EACH_EQUAL_INT(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_INT((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EACH_EQUAL_INT8(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_INT8((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EACH_EQUAL_INT16(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_INT16((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EACH_EQUAL_INT32(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_INT32((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EACH_EQUAL_INT64(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_INT64((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EACH_EQUAL_UINT(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_UINT((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EACH_EQUAL_UINT8(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_UINT8((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EACH_EQUAL_UINT16(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_UINT16((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EACH_EQUAL_UINT32(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_UINT32((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EACH_EQUAL_UINT64(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_UINT64((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EACH_EQUAL_size_t(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_UINT((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EACH_EQUAL_HEX(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_HEX32((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EACH_EQUAL_HEX8(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_HEX8((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EACH_EQUAL_HEX16(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_HEX16((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EACH_EQUAL_HEX32(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_HEX32((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EACH_EQUAL_HEX64(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_HEX64((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EACH_EQUAL_PTR(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_PTR((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EACH_EQUAL_STRING(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_STRING((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EACH_EQUAL_MEMORY(expected, actual, len, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_MEMORY((expected), (actual), (len), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EACH_EQUAL_CHAR(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_CHAR((expected), (actual), (num_elements), __LINE__, NULL) + +/* Floating Point (If Enabled) */ +#define TEST_ASSERT_FLOAT_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_FLOAT_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_FLOAT(expected, actual) UNITY_TEST_ASSERT_EQUAL_FLOAT((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_FLOAT_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_FLOAT_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EACH_EQUAL_FLOAT(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_FLOAT((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_FLOAT_IS_INF(actual) UNITY_TEST_ASSERT_FLOAT_IS_INF((actual), __LINE__, NULL) +#define TEST_ASSERT_FLOAT_IS_NEG_INF(actual) UNITY_TEST_ASSERT_FLOAT_IS_NEG_INF((actual), __LINE__, NULL) +#define TEST_ASSERT_FLOAT_IS_NAN(actual) UNITY_TEST_ASSERT_FLOAT_IS_NAN((actual), __LINE__, NULL) +#define TEST_ASSERT_FLOAT_IS_DETERMINATE(actual) UNITY_TEST_ASSERT_FLOAT_IS_DETERMINATE((actual), __LINE__, NULL) +#define TEST_ASSERT_FLOAT_IS_NOT_INF(actual) UNITY_TEST_ASSERT_FLOAT_IS_NOT_INF((actual), __LINE__, NULL) +#define TEST_ASSERT_FLOAT_IS_NOT_NEG_INF(actual) UNITY_TEST_ASSERT_FLOAT_IS_NOT_NEG_INF((actual), __LINE__, NULL) +#define TEST_ASSERT_FLOAT_IS_NOT_NAN(actual) UNITY_TEST_ASSERT_FLOAT_IS_NOT_NAN((actual), __LINE__, NULL) +#define TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE(actual) UNITY_TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE((actual), __LINE__, NULL) + +/* Double (If Enabled) */ +#define TEST_ASSERT_DOUBLE_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_DOUBLE_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_DOUBLE(expected, actual) UNITY_TEST_ASSERT_EQUAL_DOUBLE((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_DOUBLE_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_DOUBLE_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EACH_EQUAL_DOUBLE(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_DOUBLE((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_DOUBLE_IS_INF(actual) UNITY_TEST_ASSERT_DOUBLE_IS_INF((actual), __LINE__, NULL) +#define TEST_ASSERT_DOUBLE_IS_NEG_INF(actual) UNITY_TEST_ASSERT_DOUBLE_IS_NEG_INF((actual), __LINE__, NULL) +#define TEST_ASSERT_DOUBLE_IS_NAN(actual) UNITY_TEST_ASSERT_DOUBLE_IS_NAN((actual), __LINE__, NULL) +#define TEST_ASSERT_DOUBLE_IS_DETERMINATE(actual) UNITY_TEST_ASSERT_DOUBLE_IS_DETERMINATE((actual), __LINE__, NULL) +#define TEST_ASSERT_DOUBLE_IS_NOT_INF(actual) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_INF((actual), __LINE__, NULL) +#define TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF(actual) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF((actual), __LINE__, NULL) +#define TEST_ASSERT_DOUBLE_IS_NOT_NAN(actual) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NAN((actual), __LINE__, NULL) +#define TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE(actual) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE((actual), __LINE__, NULL) + +/* Shorthand */ +#ifdef UNITY_SHORTHAND_AS_OLD +#define TEST_ASSERT_EQUAL(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL(expected, actual) UNITY_TEST_ASSERT(((expected) != (actual)), __LINE__, " Expected Not-Equal") +#endif +#ifdef UNITY_SHORTHAND_AS_INT +#define TEST_ASSERT_EQUAL(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL(expected, actual) UNITY_TEST_FAIL(__LINE__, UnityStrErrShorthand) +#endif +#ifdef UNITY_SHORTHAND_AS_MEM +#define TEST_ASSERT_EQUAL(expected, actual) UNITY_TEST_ASSERT_EQUAL_MEMORY((&expected), (&actual), sizeof(expected), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL(expected, actual) UNITY_TEST_FAIL(__LINE__, UnityStrErrShorthand) +#endif +#ifdef UNITY_SHORTHAND_AS_RAW +#define TEST_ASSERT_EQUAL(expected, actual) UNITY_TEST_ASSERT(((expected) == (actual)), __LINE__, " Expected Equal") +#define TEST_ASSERT_NOT_EQUAL(expected, actual) UNITY_TEST_ASSERT(((expected) != (actual)), __LINE__, " Expected Not-Equal") +#endif +#ifdef UNITY_SHORTHAND_AS_NONE +#define TEST_ASSERT_EQUAL(expected, actual) UNITY_TEST_FAIL(__LINE__, UnityStrErrShorthand) +#define TEST_ASSERT_NOT_EQUAL(expected, actual) UNITY_TEST_FAIL(__LINE__, UnityStrErrShorthand) +#endif + +/*------------------------------------------------------- + * Test Asserts (with additional messages) + *-------------------------------------------------------*/ + +/* Boolean */ +#define TEST_ASSERT_MESSAGE(condition, message) UNITY_TEST_ASSERT( (condition), __LINE__, (message)) +#define TEST_ASSERT_TRUE_MESSAGE(condition, message) UNITY_TEST_ASSERT( (condition), __LINE__, (message)) +#define TEST_ASSERT_UNLESS_MESSAGE(condition, message) UNITY_TEST_ASSERT( !(condition), __LINE__, (message)) +#define TEST_ASSERT_FALSE_MESSAGE(condition, message) UNITY_TEST_ASSERT( !(condition), __LINE__, (message)) +#define TEST_ASSERT_NULL_MESSAGE(pointer, message) UNITY_TEST_ASSERT_NULL( (pointer), __LINE__, (message)) +#define TEST_ASSERT_NOT_NULL_MESSAGE(pointer, message) UNITY_TEST_ASSERT_NOT_NULL((pointer), __LINE__, (message)) +#define TEST_ASSERT_EMPTY_MESSAGE(pointer, message) UNITY_TEST_ASSERT_EMPTY( (pointer), __LINE__, (message)) +#define TEST_ASSERT_NOT_EMPTY_MESSAGE(pointer, message) UNITY_TEST_ASSERT_NOT_EMPTY((pointer), __LINE__, (message)) + +/* Integers (of all sizes) */ +#define TEST_ASSERT_EQUAL_INT_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_INT8_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT8((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_INT16_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT16((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_INT32_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT32((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_INT64_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT64((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_UINT_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_UINT( (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_UINT8_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_UINT8( (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_UINT16_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_UINT16( (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_UINT32_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_UINT32( (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_UINT64_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_UINT64( (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_size_t_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_UINT( (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_HEX_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_HEX32((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_HEX8_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_HEX8( (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_HEX16_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_HEX16((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_HEX32_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_HEX32((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_HEX64_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_HEX64((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_BITS_MESSAGE(mask, expected, actual, message) UNITY_TEST_ASSERT_BITS((mask), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_BITS_HIGH_MESSAGE(mask, actual, message) UNITY_TEST_ASSERT_BITS((mask), (UNITY_UINT32)(-1), (actual), __LINE__, (message)) +#define TEST_ASSERT_BITS_LOW_MESSAGE(mask, actual, message) UNITY_TEST_ASSERT_BITS((mask), (UNITY_UINT32)(0), (actual), __LINE__, (message)) +#define TEST_ASSERT_BIT_HIGH_MESSAGE(bit, actual, message) UNITY_TEST_ASSERT_BITS(((UNITY_UINT32)1 << (bit)), (UNITY_UINT32)(-1), (actual), __LINE__, (message)) +#define TEST_ASSERT_BIT_LOW_MESSAGE(bit, actual, message) UNITY_TEST_ASSERT_BITS(((UNITY_UINT32)1 << (bit)), (UNITY_UINT32)(0), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_CHAR_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_CHAR((expected), (actual), __LINE__, (message)) + +/* Integer Not Equal To (of all sizes) */ +#define TEST_ASSERT_NOT_EQUAL_INT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_INT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_INT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_INT8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_INT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_INT16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_INT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_INT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_INT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_INT64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_UINT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_UINT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_UINT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_UINT8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_UINT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_UINT16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_UINT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_UINT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_UINT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_UINT64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_size_t_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_UINT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_HEX8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_HEX8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_HEX16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_HEX16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_HEX32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_HEX32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_HEX64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_HEX64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_CHAR_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_CHAR((threshold), (actual), __LINE__, (message)) + + +/* Integer Greater Than/ Less Than (of all sizes) */ +#define TEST_ASSERT_GREATER_THAN_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_INT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_INT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_INT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_INT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_INT8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_INT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_INT16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_INT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_INT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_INT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_INT64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_UINT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_UINT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_UINT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_UINT8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_UINT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_UINT16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_UINT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_UINT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_UINT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_UINT64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_size_t_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_UINT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_HEX8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_HEX8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_HEX16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_HEX16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_HEX32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_HEX32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_HEX64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_HEX64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_CHAR_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_CHAR((threshold), (actual), __LINE__, (message)) + +#define TEST_ASSERT_LESS_THAN_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_INT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_INT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_INT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_INT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_INT8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_INT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_INT16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_INT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_INT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_INT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_INT64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_UINT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_UINT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_UINT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_UINT8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_UINT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_UINT16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_UINT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_UINT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_UINT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_UINT64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_size_t_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_UINT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_HEX8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_HEX8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_HEX16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_HEX16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_HEX32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_HEX32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_HEX64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_HEX64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_CHAR_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_CHAR((threshold), (actual), __LINE__, (message)) + +#define TEST_ASSERT_GREATER_OR_EQUAL_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_size_t_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_HEX8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_HEX16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_HEX32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_HEX64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_CHAR_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_CHAR((threshold), (actual), __LINE__, (message)) + +#define TEST_ASSERT_LESS_OR_EQUAL_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_INT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_INT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_INT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_INT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_INT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_size_t_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_HEX8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_HEX16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_HEX32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_HEX64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_CHAR_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_CHAR((threshold), (actual), __LINE__, (message)) + +/* Integer Ranges (of all sizes) */ +#define TEST_ASSERT_INT_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_INT_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_INT8_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_INT8_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_INT16_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_INT16_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_INT32_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_INT32_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_INT64_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_INT64_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_UINT_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_UINT_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_UINT8_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_UINT8_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_UINT16_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_UINT16_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_UINT32_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_UINT32_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_UINT64_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_UINT64_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_size_t_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_UINT_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_HEX_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_HEX32_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_HEX8_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_HEX8_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_HEX16_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_HEX16_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_HEX32_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_HEX32_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_HEX64_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_HEX64_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_CHAR_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_CHAR_WITHIN((delta), (expected), (actual), __LINE__, (message)) + +/* Integer Array Ranges (of all sizes) */ +#define TEST_ASSERT_INT_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_INT_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_INT8_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_INT8_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_INT16_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_INT16_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_INT32_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_INT32_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_INT64_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_INT64_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_UINT_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_UINT_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_UINT8_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_UINT8_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_UINT16_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_UINT16_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_UINT32_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_UINT32_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_UINT64_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_UINT64_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_size_t_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_UINT_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_HEX_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_HEX32_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_HEX8_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_HEX8_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_HEX16_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_HEX16_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_HEX32_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_HEX32_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_HEX64_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_HEX64_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_CHAR_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_CHAR_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) + + +/* Structs and Strings */ +#define TEST_ASSERT_EQUAL_PTR_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_PTR((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_STRING((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_STRING_LEN_MESSAGE(expected, actual, len, message) UNITY_TEST_ASSERT_EQUAL_STRING_LEN((expected), (actual), (len), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_MEMORY_MESSAGE(expected, actual, len, message) UNITY_TEST_ASSERT_EQUAL_MEMORY((expected), (actual), (len), __LINE__, (message)) + +/* Arrays */ +#define TEST_ASSERT_EQUAL_INT_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_INT_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_INT8_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_INT8_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_INT16_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_INT16_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_INT32_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_INT32_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_INT64_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_INT64_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_UINT_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_UINT_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_UINT8_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_UINT8_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_UINT16_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_UINT16_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_UINT32_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_UINT32_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_UINT64_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_UINT64_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_size_t_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_UINT_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_HEX_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_HEX32_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_HEX8_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_HEX8_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_HEX16_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_HEX16_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_HEX32_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_HEX32_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_HEX64_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_HEX64_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_PTR_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_PTR_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_STRING_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_STRING_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_MEMORY_ARRAY_MESSAGE(expected, actual, len, num_elements, message) UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY((expected), (actual), (len), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_CHAR_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_CHAR_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) + +/* Arrays Compared To Single Value*/ +#define TEST_ASSERT_EACH_EQUAL_INT_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_INT((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EACH_EQUAL_INT8_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_INT8((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EACH_EQUAL_INT16_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_INT16((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EACH_EQUAL_INT32_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_INT32((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EACH_EQUAL_INT64_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_INT64((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EACH_EQUAL_UINT_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_UINT((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EACH_EQUAL_UINT8_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_UINT8((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EACH_EQUAL_UINT16_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_UINT16((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EACH_EQUAL_UINT32_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_UINT32((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EACH_EQUAL_UINT64_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_UINT64((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EACH_EQUAL_size_t_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_UINT((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EACH_EQUAL_HEX_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_HEX32((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EACH_EQUAL_HEX8_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_HEX8((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EACH_EQUAL_HEX16_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_HEX16((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EACH_EQUAL_HEX32_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_HEX32((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EACH_EQUAL_HEX64_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_HEX64((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EACH_EQUAL_PTR_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_PTR((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EACH_EQUAL_STRING_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_STRING((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EACH_EQUAL_MEMORY_MESSAGE(expected, actual, len, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_MEMORY((expected), (actual), (len), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EACH_EQUAL_CHAR_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_CHAR((expected), (actual), (num_elements), __LINE__, (message)) + +/* Floating Point (If Enabled) */ +#define TEST_ASSERT_FLOAT_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_FLOAT_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_FLOAT_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_FLOAT((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_FLOAT_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_FLOAT_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EACH_EQUAL_FLOAT_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_FLOAT((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_FLOAT_IS_INF_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_INF((actual), __LINE__, (message)) +#define TEST_ASSERT_FLOAT_IS_NEG_INF_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_NEG_INF((actual), __LINE__, (message)) +#define TEST_ASSERT_FLOAT_IS_NAN_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_NAN((actual), __LINE__, (message)) +#define TEST_ASSERT_FLOAT_IS_DETERMINATE_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_DETERMINATE((actual), __LINE__, (message)) +#define TEST_ASSERT_FLOAT_IS_NOT_INF_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_NOT_INF((actual), __LINE__, (message)) +#define TEST_ASSERT_FLOAT_IS_NOT_NEG_INF_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_NOT_NEG_INF((actual), __LINE__, (message)) +#define TEST_ASSERT_FLOAT_IS_NOT_NAN_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_NOT_NAN((actual), __LINE__, (message)) +#define TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE((actual), __LINE__, (message)) + +/* Double (If Enabled) */ +#define TEST_ASSERT_DOUBLE_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_DOUBLE_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_DOUBLE_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_DOUBLE((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_DOUBLE_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_DOUBLE_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EACH_EQUAL_DOUBLE_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_DOUBLE((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_DOUBLE_IS_INF_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_INF((actual), __LINE__, (message)) +#define TEST_ASSERT_DOUBLE_IS_NEG_INF_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_NEG_INF((actual), __LINE__, (message)) +#define TEST_ASSERT_DOUBLE_IS_NAN_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_NAN((actual), __LINE__, (message)) +#define TEST_ASSERT_DOUBLE_IS_DETERMINATE_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_DETERMINATE((actual), __LINE__, (message)) +#define TEST_ASSERT_DOUBLE_IS_NOT_INF_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_INF((actual), __LINE__, (message)) +#define TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF((actual), __LINE__, (message)) +#define TEST_ASSERT_DOUBLE_IS_NOT_NAN_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NAN((actual), __LINE__, (message)) +#define TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE((actual), __LINE__, (message)) + +/* Shorthand */ +#ifdef UNITY_SHORTHAND_AS_OLD +#define TEST_ASSERT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT(((expected) != (actual)), __LINE__, (message)) +#endif +#ifdef UNITY_SHORTHAND_AS_INT +#define TEST_ASSERT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, message) +#define TEST_ASSERT_NOT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_FAIL(__LINE__, UnityStrErrShorthand) +#endif +#ifdef UNITY_SHORTHAND_AS_MEM +#define TEST_ASSERT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_MEMORY((&expected), (&actual), sizeof(expected), __LINE__, message) +#define TEST_ASSERT_NOT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_FAIL(__LINE__, UnityStrErrShorthand) +#endif +#ifdef UNITY_SHORTHAND_AS_RAW +#define TEST_ASSERT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT(((expected) == (actual)), __LINE__, message) +#define TEST_ASSERT_NOT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT(((expected) != (actual)), __LINE__, message) +#endif +#ifdef UNITY_SHORTHAND_AS_NONE +#define TEST_ASSERT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_FAIL(__LINE__, UnityStrErrShorthand) +#define TEST_ASSERT_NOT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_FAIL(__LINE__, UnityStrErrShorthand) +#endif + +/* end of UNITY_FRAMEWORK_H */ +#ifdef __cplusplus +} +#endif +#endif diff --git a/c/hello-world/test-framework/unity_internals.h b/c/hello-world/test-framework/unity_internals.h new file mode 100644 index 0000000..79c305e --- /dev/null +++ b/c/hello-world/test-framework/unity_internals.h @@ -0,0 +1,1039 @@ +/* ========================================== + Unity Project - A Test Framework for C + Copyright (c) 2007-21 Mike Karlesky, Mark VanderVoord, Greg Williams + [Released under MIT License. Please refer to license.txt for details] +========================================== */ + +#ifndef UNITY_INTERNALS_H +#define UNITY_INTERNALS_H + +#ifdef UNITY_INCLUDE_CONFIG_H +#include "unity_config.h" +#endif + +#ifndef UNITY_EXCLUDE_SETJMP_H +#include +#endif + +#ifndef UNITY_EXCLUDE_MATH_H +#include +#endif + +#ifndef UNITY_EXCLUDE_STDDEF_H +#include +#endif + +#ifdef UNITY_INCLUDE_PRINT_FORMATTED +#include +#endif + +/* Unity Attempts to Auto-Detect Integer Types + * Attempt 1: UINT_MAX, ULONG_MAX in , or default to 32 bits + * Attempt 2: UINTPTR_MAX in , or default to same size as long + * The user may override any of these derived constants: + * UNITY_INT_WIDTH, UNITY_LONG_WIDTH, UNITY_POINTER_WIDTH */ +#ifndef UNITY_EXCLUDE_STDINT_H +#include +#endif + +#ifndef UNITY_EXCLUDE_LIMITS_H +#include +#endif + +#if defined __GNUC__ +# define UNITY_FUNCTION_ATTR(a) __attribute__((a)) +#else +# define UNITY_FUNCTION_ATTR(a) /* ignore */ +#endif + +/*------------------------------------------------------- + * Guess Widths If Not Specified + *-------------------------------------------------------*/ + +/* Determine the size of an int, if not already specified. + * We cannot use sizeof(int), because it is not yet defined + * at this stage in the translation of the C program. + * Also sizeof(int) does return the size in addressable units on all platforms, + * which may not necessarily be the size in bytes. + * Therefore, infer it from UINT_MAX if possible. */ +#ifndef UNITY_INT_WIDTH + #ifdef UINT_MAX + #if (UINT_MAX == 0xFFFF) + #define UNITY_INT_WIDTH (16) + #elif (UINT_MAX == 0xFFFFFFFF) + #define UNITY_INT_WIDTH (32) + #elif (UINT_MAX == 0xFFFFFFFFFFFFFFFF) + #define UNITY_INT_WIDTH (64) + #endif + #else /* Set to default */ + #define UNITY_INT_WIDTH (32) + #endif /* UINT_MAX */ +#endif + +/* Determine the size of a long, if not already specified. */ +#ifndef UNITY_LONG_WIDTH + #ifdef ULONG_MAX + #if (ULONG_MAX == 0xFFFF) + #define UNITY_LONG_WIDTH (16) + #elif (ULONG_MAX == 0xFFFFFFFF) + #define UNITY_LONG_WIDTH (32) + #elif (ULONG_MAX == 0xFFFFFFFFFFFFFFFF) + #define UNITY_LONG_WIDTH (64) + #endif + #else /* Set to default */ + #define UNITY_LONG_WIDTH (32) + #endif /* ULONG_MAX */ +#endif + +/* Determine the size of a pointer, if not already specified. */ +#ifndef UNITY_POINTER_WIDTH + #ifdef UINTPTR_MAX + #if (UINTPTR_MAX <= 0xFFFF) + #define UNITY_POINTER_WIDTH (16) + #elif (UINTPTR_MAX <= 0xFFFFFFFF) + #define UNITY_POINTER_WIDTH (32) + #elif (UINTPTR_MAX <= 0xFFFFFFFFFFFFFFFF) + #define UNITY_POINTER_WIDTH (64) + #endif + #else /* Set to default */ + #define UNITY_POINTER_WIDTH UNITY_LONG_WIDTH + #endif /* UINTPTR_MAX */ +#endif + +/*------------------------------------------------------- + * Int Support (Define types based on detected sizes) + *-------------------------------------------------------*/ + +#if (UNITY_INT_WIDTH == 32) + typedef unsigned char UNITY_UINT8; + typedef unsigned short UNITY_UINT16; + typedef unsigned int UNITY_UINT32; + typedef signed char UNITY_INT8; + typedef signed short UNITY_INT16; + typedef signed int UNITY_INT32; +#elif (UNITY_INT_WIDTH == 16) + typedef unsigned char UNITY_UINT8; + typedef unsigned int UNITY_UINT16; + typedef unsigned long UNITY_UINT32; + typedef signed char UNITY_INT8; + typedef signed int UNITY_INT16; + typedef signed long UNITY_INT32; +#else + #error Invalid UNITY_INT_WIDTH specified! (16 or 32 are supported) +#endif + +/*------------------------------------------------------- + * 64-bit Support + *-------------------------------------------------------*/ + +/* Auto-detect 64 Bit Support */ +#ifndef UNITY_SUPPORT_64 + #if UNITY_LONG_WIDTH == 64 || UNITY_POINTER_WIDTH == 64 + #define UNITY_SUPPORT_64 + #endif +#endif + +/* 64-Bit Support Dependent Configuration */ +#ifndef UNITY_SUPPORT_64 + /* No 64-bit Support */ + typedef UNITY_UINT32 UNITY_UINT; + typedef UNITY_INT32 UNITY_INT; + #define UNITY_MAX_NIBBLES (8) /* Maximum number of nibbles in a UNITY_(U)INT */ +#else + /* 64-bit Support */ + #if (UNITY_LONG_WIDTH == 32) + typedef unsigned long long UNITY_UINT64; + typedef signed long long UNITY_INT64; + #elif (UNITY_LONG_WIDTH == 64) + typedef unsigned long UNITY_UINT64; + typedef signed long UNITY_INT64; + #else + #error Invalid UNITY_LONG_WIDTH specified! (32 or 64 are supported) + #endif + typedef UNITY_UINT64 UNITY_UINT; + typedef UNITY_INT64 UNITY_INT; + #define UNITY_MAX_NIBBLES (16) /* Maximum number of nibbles in a UNITY_(U)INT */ +#endif + +/*------------------------------------------------------- + * Pointer Support + *-------------------------------------------------------*/ + +#if (UNITY_POINTER_WIDTH == 32) + #define UNITY_PTR_TO_INT UNITY_INT32 + #define UNITY_DISPLAY_STYLE_POINTER UNITY_DISPLAY_STYLE_HEX32 +#elif (UNITY_POINTER_WIDTH == 64) + #define UNITY_PTR_TO_INT UNITY_INT64 + #define UNITY_DISPLAY_STYLE_POINTER UNITY_DISPLAY_STYLE_HEX64 +#elif (UNITY_POINTER_WIDTH == 16) + #define UNITY_PTR_TO_INT UNITY_INT16 + #define UNITY_DISPLAY_STYLE_POINTER UNITY_DISPLAY_STYLE_HEX16 +#else + #error Invalid UNITY_POINTER_WIDTH specified! (16, 32 or 64 are supported) +#endif + +#ifndef UNITY_PTR_ATTRIBUTE + #define UNITY_PTR_ATTRIBUTE +#endif + +#ifndef UNITY_INTERNAL_PTR + #define UNITY_INTERNAL_PTR UNITY_PTR_ATTRIBUTE const void* +#endif + +/*------------------------------------------------------- + * Float Support + *-------------------------------------------------------*/ + +#ifdef UNITY_EXCLUDE_FLOAT + +/* No Floating Point Support */ +#ifndef UNITY_EXCLUDE_DOUBLE +#define UNITY_EXCLUDE_DOUBLE /* Remove double when excluding float support */ +#endif +#ifndef UNITY_EXCLUDE_FLOAT_PRINT +#define UNITY_EXCLUDE_FLOAT_PRINT +#endif + +#else + +/* Floating Point Support */ +#ifndef UNITY_FLOAT_PRECISION +#define UNITY_FLOAT_PRECISION (0.00001f) +#endif +#ifndef UNITY_FLOAT_TYPE +#define UNITY_FLOAT_TYPE float +#endif +typedef UNITY_FLOAT_TYPE UNITY_FLOAT; + +/* isinf & isnan macros should be provided by math.h */ +#ifndef isinf +/* The value of Inf - Inf is NaN */ +#define isinf(n) (isnan((n) - (n)) && !isnan(n)) +#endif + +#ifndef isnan +/* NaN is the only floating point value that does NOT equal itself. + * Therefore if n != n, then it is NaN. */ +#define isnan(n) ((n != n) ? 1 : 0) +#endif + +#endif + +/*------------------------------------------------------- + * Double Float Support + *-------------------------------------------------------*/ + +/* unlike float, we DON'T include by default */ +#if defined(UNITY_EXCLUDE_DOUBLE) || !defined(UNITY_INCLUDE_DOUBLE) + + /* No Floating Point Support */ + #ifndef UNITY_EXCLUDE_DOUBLE + #define UNITY_EXCLUDE_DOUBLE + #else + #undef UNITY_INCLUDE_DOUBLE + #endif + + #ifndef UNITY_EXCLUDE_FLOAT + #ifndef UNITY_DOUBLE_TYPE + #define UNITY_DOUBLE_TYPE double + #endif + typedef UNITY_FLOAT UNITY_DOUBLE; + /* For parameter in UnityPrintFloat(UNITY_DOUBLE), which aliases to double or float */ + #endif + +#else + + /* Double Floating Point Support */ + #ifndef UNITY_DOUBLE_PRECISION + #define UNITY_DOUBLE_PRECISION (1e-12) + #endif + + #ifndef UNITY_DOUBLE_TYPE + #define UNITY_DOUBLE_TYPE double + #endif + typedef UNITY_DOUBLE_TYPE UNITY_DOUBLE; + +#endif + +/*------------------------------------------------------- + * Output Method: stdout (DEFAULT) + *-------------------------------------------------------*/ +#ifndef UNITY_OUTPUT_CHAR + /* Default to using putchar, which is defined in stdio.h */ + #include + #define UNITY_OUTPUT_CHAR(a) (void)putchar(a) +#else + /* If defined as something else, make sure we declare it here so it's ready for use */ + #ifdef UNITY_OUTPUT_CHAR_HEADER_DECLARATION + extern void UNITY_OUTPUT_CHAR_HEADER_DECLARATION; + #endif +#endif + +#ifndef UNITY_OUTPUT_FLUSH + #ifdef UNITY_USE_FLUSH_STDOUT + /* We want to use the stdout flush utility */ + #include + #define UNITY_OUTPUT_FLUSH() (void)fflush(stdout) + #else + /* We've specified nothing, therefore flush should just be ignored */ + #define UNITY_OUTPUT_FLUSH() + #endif +#else + /* If defined as something else, make sure we declare it here so it's ready for use */ + #ifdef UNITY_OUTPUT_FLUSH_HEADER_DECLARATION + extern void UNITY_OUTPUT_FLUSH_HEADER_DECLARATION; + #endif +#endif + +#ifndef UNITY_OUTPUT_FLUSH +#define UNITY_FLUSH_CALL() +#else +#define UNITY_FLUSH_CALL() UNITY_OUTPUT_FLUSH() +#endif + +#ifndef UNITY_PRINT_EOL +#define UNITY_PRINT_EOL() UNITY_OUTPUT_CHAR('\n') +#endif + +#ifndef UNITY_OUTPUT_START +#define UNITY_OUTPUT_START() +#endif + +#ifndef UNITY_OUTPUT_COMPLETE +#define UNITY_OUTPUT_COMPLETE() +#endif + +#ifdef UNITY_INCLUDE_EXEC_TIME + #if !defined(UNITY_EXEC_TIME_START) && \ + !defined(UNITY_EXEC_TIME_STOP) && \ + !defined(UNITY_PRINT_EXEC_TIME) && \ + !defined(UNITY_TIME_TYPE) + /* If none any of these macros are defined then try to provide a default implementation */ + + #if defined(UNITY_CLOCK_MS) + /* This is a simple way to get a default implementation on platforms that support getting a millisecond counter */ + #define UNITY_TIME_TYPE UNITY_UINT + #define UNITY_EXEC_TIME_START() Unity.CurrentTestStartTime = UNITY_CLOCK_MS() + #define UNITY_EXEC_TIME_STOP() Unity.CurrentTestStopTime = UNITY_CLOCK_MS() + #define UNITY_PRINT_EXEC_TIME() { \ + UNITY_UINT execTimeMs = (Unity.CurrentTestStopTime - Unity.CurrentTestStartTime); \ + UnityPrint(" ("); \ + UnityPrintNumberUnsigned(execTimeMs); \ + UnityPrint(" ms)"); \ + } + #elif defined(_WIN32) + #include + #define UNITY_TIME_TYPE clock_t + #define UNITY_GET_TIME(t) t = (clock_t)((clock() * 1000) / CLOCKS_PER_SEC) + #define UNITY_EXEC_TIME_START() UNITY_GET_TIME(Unity.CurrentTestStartTime) + #define UNITY_EXEC_TIME_STOP() UNITY_GET_TIME(Unity.CurrentTestStopTime) + #define UNITY_PRINT_EXEC_TIME() { \ + UNITY_UINT execTimeMs = (Unity.CurrentTestStopTime - Unity.CurrentTestStartTime); \ + UnityPrint(" ("); \ + UnityPrintNumberUnsigned(execTimeMs); \ + UnityPrint(" ms)"); \ + } + #elif defined(__unix__) + #include + #define UNITY_TIME_TYPE struct timespec + #define UNITY_GET_TIME(t) clock_gettime(CLOCK_MONOTONIC, &t) + #define UNITY_EXEC_TIME_START() UNITY_GET_TIME(Unity.CurrentTestStartTime) + #define UNITY_EXEC_TIME_STOP() UNITY_GET_TIME(Unity.CurrentTestStopTime) + #define UNITY_PRINT_EXEC_TIME() { \ + UNITY_UINT execTimeMs = ((Unity.CurrentTestStopTime.tv_sec - Unity.CurrentTestStartTime.tv_sec) * 1000L); \ + execTimeMs += ((Unity.CurrentTestStopTime.tv_nsec - Unity.CurrentTestStartTime.tv_nsec) / 1000000L); \ + UnityPrint(" ("); \ + UnityPrintNumberUnsigned(execTimeMs); \ + UnityPrint(" ms)"); \ + } + #endif + #endif +#endif + +#ifndef UNITY_EXEC_TIME_START +#define UNITY_EXEC_TIME_START() do{}while(0) +#endif + +#ifndef UNITY_EXEC_TIME_STOP +#define UNITY_EXEC_TIME_STOP() do{}while(0) +#endif + +#ifndef UNITY_TIME_TYPE +#define UNITY_TIME_TYPE UNITY_UINT +#endif + +#ifndef UNITY_PRINT_EXEC_TIME +#define UNITY_PRINT_EXEC_TIME() do{}while(0) +#endif + +/*------------------------------------------------------- + * Footprint + *-------------------------------------------------------*/ + +#ifndef UNITY_LINE_TYPE +#define UNITY_LINE_TYPE UNITY_UINT +#endif + +#ifndef UNITY_COUNTER_TYPE +#define UNITY_COUNTER_TYPE UNITY_UINT +#endif + +/*------------------------------------------------------- + * Internal Structs Needed + *-------------------------------------------------------*/ + +typedef void (*UnityTestFunction)(void); + +#define UNITY_DISPLAY_RANGE_INT (0x10) +#define UNITY_DISPLAY_RANGE_UINT (0x20) +#define UNITY_DISPLAY_RANGE_HEX (0x40) +#define UNITY_DISPLAY_RANGE_CHAR (0x80) + +typedef enum +{ + UNITY_DISPLAY_STYLE_INT = (UNITY_INT_WIDTH / 8) + UNITY_DISPLAY_RANGE_INT, + UNITY_DISPLAY_STYLE_INT8 = 1 + UNITY_DISPLAY_RANGE_INT, + UNITY_DISPLAY_STYLE_INT16 = 2 + UNITY_DISPLAY_RANGE_INT, + UNITY_DISPLAY_STYLE_INT32 = 4 + UNITY_DISPLAY_RANGE_INT, +#ifdef UNITY_SUPPORT_64 + UNITY_DISPLAY_STYLE_INT64 = 8 + UNITY_DISPLAY_RANGE_INT, +#endif + + UNITY_DISPLAY_STYLE_UINT = (UNITY_INT_WIDTH / 8) + UNITY_DISPLAY_RANGE_UINT, + UNITY_DISPLAY_STYLE_UINT8 = 1 + UNITY_DISPLAY_RANGE_UINT, + UNITY_DISPLAY_STYLE_UINT16 = 2 + UNITY_DISPLAY_RANGE_UINT, + UNITY_DISPLAY_STYLE_UINT32 = 4 + UNITY_DISPLAY_RANGE_UINT, +#ifdef UNITY_SUPPORT_64 + UNITY_DISPLAY_STYLE_UINT64 = 8 + UNITY_DISPLAY_RANGE_UINT, +#endif + + UNITY_DISPLAY_STYLE_HEX8 = 1 + UNITY_DISPLAY_RANGE_HEX, + UNITY_DISPLAY_STYLE_HEX16 = 2 + UNITY_DISPLAY_RANGE_HEX, + UNITY_DISPLAY_STYLE_HEX32 = 4 + UNITY_DISPLAY_RANGE_HEX, +#ifdef UNITY_SUPPORT_64 + UNITY_DISPLAY_STYLE_HEX64 = 8 + UNITY_DISPLAY_RANGE_HEX, +#endif + + UNITY_DISPLAY_STYLE_CHAR = 1 + UNITY_DISPLAY_RANGE_CHAR + UNITY_DISPLAY_RANGE_INT, + + UNITY_DISPLAY_STYLE_UNKNOWN +} UNITY_DISPLAY_STYLE_T; + +typedef enum +{ + UNITY_WITHIN = 0x0, + UNITY_EQUAL_TO = 0x1, + UNITY_GREATER_THAN = 0x2, + UNITY_GREATER_OR_EQUAL = 0x2 + UNITY_EQUAL_TO, + UNITY_SMALLER_THAN = 0x4, + UNITY_SMALLER_OR_EQUAL = 0x4 + UNITY_EQUAL_TO, + UNITY_NOT_EQUAL = 0x0, + UNITY_UNKNOWN +} UNITY_COMPARISON_T; + +#ifndef UNITY_EXCLUDE_FLOAT +typedef enum UNITY_FLOAT_TRAIT +{ + UNITY_FLOAT_IS_NOT_INF = 0, + UNITY_FLOAT_IS_INF, + UNITY_FLOAT_IS_NOT_NEG_INF, + UNITY_FLOAT_IS_NEG_INF, + UNITY_FLOAT_IS_NOT_NAN, + UNITY_FLOAT_IS_NAN, + UNITY_FLOAT_IS_NOT_DET, + UNITY_FLOAT_IS_DET, + UNITY_FLOAT_INVALID_TRAIT +} UNITY_FLOAT_TRAIT_T; +#endif + +typedef enum +{ + UNITY_ARRAY_TO_VAL = 0, + UNITY_ARRAY_TO_ARRAY, + UNITY_ARRAY_UNKNOWN +} UNITY_FLAGS_T; + +struct UNITY_STORAGE_T +{ + const char* TestFile; + const char* CurrentTestName; +#ifndef UNITY_EXCLUDE_DETAILS + const char* CurrentDetail1; + const char* CurrentDetail2; +#endif + UNITY_LINE_TYPE CurrentTestLineNumber; + UNITY_COUNTER_TYPE NumberOfTests; + UNITY_COUNTER_TYPE TestFailures; + UNITY_COUNTER_TYPE TestIgnores; + UNITY_COUNTER_TYPE CurrentTestFailed; + UNITY_COUNTER_TYPE CurrentTestIgnored; +#ifdef UNITY_INCLUDE_EXEC_TIME + UNITY_TIME_TYPE CurrentTestStartTime; + UNITY_TIME_TYPE CurrentTestStopTime; +#endif +#ifndef UNITY_EXCLUDE_SETJMP_H + jmp_buf AbortFrame; +#endif +}; + +extern struct UNITY_STORAGE_T Unity; + +/*------------------------------------------------------- + * Test Suite Management + *-------------------------------------------------------*/ + +void UnityBegin(const char* filename); +int UnityEnd(void); +void UnitySetTestFile(const char* filename); +void UnityConcludeTest(void); + +#ifndef RUN_TEST +void UnityDefaultTestRun(UnityTestFunction Func, const char* FuncName, const int FuncLineNum); +#else +#define UNITY_SKIP_DEFAULT_RUNNER +#endif + +/*------------------------------------------------------- + * Details Support + *-------------------------------------------------------*/ + +#ifdef UNITY_EXCLUDE_DETAILS +#define UNITY_CLR_DETAILS() +#define UNITY_SET_DETAIL(d1) +#define UNITY_SET_DETAILS(d1,d2) +#else +#define UNITY_CLR_DETAILS() { Unity.CurrentDetail1 = 0; Unity.CurrentDetail2 = 0; } +#define UNITY_SET_DETAIL(d1) { Unity.CurrentDetail1 = (d1); Unity.CurrentDetail2 = 0; } +#define UNITY_SET_DETAILS(d1,d2) { Unity.CurrentDetail1 = (d1); Unity.CurrentDetail2 = (d2); } + +#ifndef UNITY_DETAIL1_NAME +#define UNITY_DETAIL1_NAME "Function" +#endif + +#ifndef UNITY_DETAIL2_NAME +#define UNITY_DETAIL2_NAME "Argument" +#endif +#endif + +#ifdef UNITY_PRINT_TEST_CONTEXT +void UNITY_PRINT_TEST_CONTEXT(void); +#endif + +/*------------------------------------------------------- + * Test Output + *-------------------------------------------------------*/ + +void UnityPrint(const char* string); + +#ifdef UNITY_INCLUDE_PRINT_FORMATTED +void UnityPrintF(const UNITY_LINE_TYPE line, const char* format, ...); +#endif + +void UnityPrintLen(const char* string, const UNITY_UINT32 length); +void UnityPrintMask(const UNITY_UINT mask, const UNITY_UINT number); +void UnityPrintNumberByStyle(const UNITY_INT number, const UNITY_DISPLAY_STYLE_T style); +void UnityPrintNumber(const UNITY_INT number_to_print); +void UnityPrintNumberUnsigned(const UNITY_UINT number); +void UnityPrintNumberHex(const UNITY_UINT number, const char nibbles_to_print); + +#ifndef UNITY_EXCLUDE_FLOAT_PRINT +void UnityPrintFloat(const UNITY_DOUBLE input_number); +#endif + +/*------------------------------------------------------- + * Test Assertion Functions + *------------------------------------------------------- + * Use the macros below this section instead of calling + * these directly. The macros have a consistent naming + * convention and will pull in file and line information + * for you. */ + +void UnityAssertEqualNumber(const UNITY_INT expected, + const UNITY_INT actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_DISPLAY_STYLE_T style); + +void UnityAssertGreaterOrLessOrEqualNumber(const UNITY_INT threshold, + const UNITY_INT actual, + const UNITY_COMPARISON_T compare, + const char *msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_DISPLAY_STYLE_T style); + +void UnityAssertEqualIntArray(UNITY_INTERNAL_PTR expected, + UNITY_INTERNAL_PTR actual, + const UNITY_UINT32 num_elements, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_DISPLAY_STYLE_T style, + const UNITY_FLAGS_T flags); + +void UnityAssertBits(const UNITY_INT mask, + const UNITY_INT expected, + const UNITY_INT actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber); + +void UnityAssertEqualString(const char* expected, + const char* actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber); + +void UnityAssertEqualStringLen(const char* expected, + const char* actual, + const UNITY_UINT32 length, + const char* msg, + const UNITY_LINE_TYPE lineNumber); + +void UnityAssertEqualStringArray( UNITY_INTERNAL_PTR expected, + const char** actual, + const UNITY_UINT32 num_elements, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_FLAGS_T flags); + +void UnityAssertEqualMemory( UNITY_INTERNAL_PTR expected, + UNITY_INTERNAL_PTR actual, + const UNITY_UINT32 length, + const UNITY_UINT32 num_elements, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_FLAGS_T flags); + +void UnityAssertNumbersWithin(const UNITY_UINT delta, + const UNITY_INT expected, + const UNITY_INT actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_DISPLAY_STYLE_T style); + +void UnityAssertNumbersArrayWithin(const UNITY_UINT delta, + UNITY_INTERNAL_PTR expected, + UNITY_INTERNAL_PTR actual, + const UNITY_UINT32 num_elements, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_DISPLAY_STYLE_T style, + const UNITY_FLAGS_T flags); + +#ifndef UNITY_EXCLUDE_SETJMP_H +void UnityFail(const char* message, const UNITY_LINE_TYPE line) UNITY_FUNCTION_ATTR(noreturn); +void UnityIgnore(const char* message, const UNITY_LINE_TYPE line) UNITY_FUNCTION_ATTR(noreturn); +#else +void UnityFail(const char* message, const UNITY_LINE_TYPE line); +void UnityIgnore(const char* message, const UNITY_LINE_TYPE line); +#endif + +void UnityMessage(const char* message, const UNITY_LINE_TYPE line); + +#ifndef UNITY_EXCLUDE_FLOAT +void UnityAssertFloatsWithin(const UNITY_FLOAT delta, + const UNITY_FLOAT expected, + const UNITY_FLOAT actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber); + +void UnityAssertEqualFloatArray(UNITY_PTR_ATTRIBUTE const UNITY_FLOAT* expected, + UNITY_PTR_ATTRIBUTE const UNITY_FLOAT* actual, + const UNITY_UINT32 num_elements, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_FLAGS_T flags); + +void UnityAssertFloatSpecial(const UNITY_FLOAT actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_FLOAT_TRAIT_T style); +#endif + +#ifndef UNITY_EXCLUDE_DOUBLE +void UnityAssertDoublesWithin(const UNITY_DOUBLE delta, + const UNITY_DOUBLE expected, + const UNITY_DOUBLE actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber); + +void UnityAssertEqualDoubleArray(UNITY_PTR_ATTRIBUTE const UNITY_DOUBLE* expected, + UNITY_PTR_ATTRIBUTE const UNITY_DOUBLE* actual, + const UNITY_UINT32 num_elements, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_FLAGS_T flags); + +void UnityAssertDoubleSpecial(const UNITY_DOUBLE actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_FLOAT_TRAIT_T style); +#endif + +/*------------------------------------------------------- + * Helpers + *-------------------------------------------------------*/ + +UNITY_INTERNAL_PTR UnityNumToPtr(const UNITY_INT num, const UNITY_UINT8 size); +#ifndef UNITY_EXCLUDE_FLOAT +UNITY_INTERNAL_PTR UnityFloatToPtr(const float num); +#endif +#ifndef UNITY_EXCLUDE_DOUBLE +UNITY_INTERNAL_PTR UnityDoubleToPtr(const double num); +#endif + +/*------------------------------------------------------- + * Error Strings We Might Need + *-------------------------------------------------------*/ + +extern const char UnityStrOk[]; +extern const char UnityStrPass[]; +extern const char UnityStrFail[]; +extern const char UnityStrIgnore[]; + +extern const char UnityStrErrFloat[]; +extern const char UnityStrErrDouble[]; +extern const char UnityStrErr64[]; +extern const char UnityStrErrShorthand[]; + +/*------------------------------------------------------- + * Test Running Macros + *-------------------------------------------------------*/ + +#ifndef UNITY_EXCLUDE_SETJMP_H +#define TEST_PROTECT() (setjmp(Unity.AbortFrame) == 0) +#define TEST_ABORT() longjmp(Unity.AbortFrame, 1) +#else +#define TEST_PROTECT() 1 +#define TEST_ABORT() return +#endif + +/* This tricky series of macros gives us an optional line argument to treat it as RUN_TEST(func, num=__LINE__) */ +#ifndef RUN_TEST +#ifdef __STDC_VERSION__ +#if __STDC_VERSION__ >= 199901L +#define UNITY_SUPPORT_VARIADIC_MACROS +#endif +#endif +#ifdef UNITY_SUPPORT_VARIADIC_MACROS +#define RUN_TEST(...) RUN_TEST_AT_LINE(__VA_ARGS__, __LINE__, throwaway) +#define RUN_TEST_AT_LINE(func, line, ...) UnityDefaultTestRun(func, #func, line) +#endif +#endif + +/* If we can't do the tricky version, we'll just have to require them to always include the line number */ +#ifndef RUN_TEST +#ifdef CMOCK +#define RUN_TEST(func, num) UnityDefaultTestRun(func, #func, num) +#else +#define RUN_TEST(func) UnityDefaultTestRun(func, #func, __LINE__) +#endif +#endif + +#define TEST_LINE_NUM (Unity.CurrentTestLineNumber) +#define TEST_IS_IGNORED (Unity.CurrentTestIgnored) +#define UNITY_NEW_TEST(a) \ + Unity.CurrentTestName = (a); \ + Unity.CurrentTestLineNumber = (UNITY_LINE_TYPE)(__LINE__); \ + Unity.NumberOfTests++; + +#ifndef UNITY_BEGIN +#define UNITY_BEGIN() UnityBegin(__FILE__) +#endif + +#ifndef UNITY_END +#define UNITY_END() UnityEnd() +#endif + +#ifndef UNITY_SHORTHAND_AS_INT +#ifndef UNITY_SHORTHAND_AS_MEM +#ifndef UNITY_SHORTHAND_AS_NONE +#ifndef UNITY_SHORTHAND_AS_RAW +#define UNITY_SHORTHAND_AS_OLD +#endif +#endif +#endif +#endif + +/*----------------------------------------------- + * Command Line Argument Support + *-----------------------------------------------*/ + +#ifdef UNITY_USE_COMMAND_LINE_ARGS +int UnityParseOptions(int argc, char** argv); +int UnityTestMatches(void); +#endif + +/*------------------------------------------------------- + * Basic Fail and Ignore + *-------------------------------------------------------*/ + +#define UNITY_TEST_FAIL(line, message) UnityFail( (message), (UNITY_LINE_TYPE)(line)) +#define UNITY_TEST_IGNORE(line, message) UnityIgnore( (message), (UNITY_LINE_TYPE)(line)) + +/*------------------------------------------------------- + * Test Asserts + *-------------------------------------------------------*/ + +#define UNITY_TEST_ASSERT(condition, line, message) do {if (condition) {} else {UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), (message));}} while(0) +#define UNITY_TEST_ASSERT_NULL(pointer, line, message) UNITY_TEST_ASSERT(((pointer) == NULL), (UNITY_LINE_TYPE)(line), (message)) +#define UNITY_TEST_ASSERT_NOT_NULL(pointer, line, message) UNITY_TEST_ASSERT(((pointer) != NULL), (UNITY_LINE_TYPE)(line), (message)) +#define UNITY_TEST_ASSERT_EMPTY(pointer, line, message) UNITY_TEST_ASSERT(((pointer[0]) == 0), (UNITY_LINE_TYPE)(line), (message)) +#define UNITY_TEST_ASSERT_NOT_EMPTY(pointer, line, message) UNITY_TEST_ASSERT(((pointer[0]) != 0), (UNITY_LINE_TYPE)(line), (message)) + +#define UNITY_TEST_ASSERT_EQUAL_INT(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) +#define UNITY_TEST_ASSERT_EQUAL_INT8(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(UNITY_INT8 )(expected), (UNITY_INT)(UNITY_INT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) +#define UNITY_TEST_ASSERT_EQUAL_INT16(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(UNITY_INT16)(expected), (UNITY_INT)(UNITY_INT16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16) +#define UNITY_TEST_ASSERT_EQUAL_INT32(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(UNITY_INT32)(expected), (UNITY_INT)(UNITY_INT32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32) +#define UNITY_TEST_ASSERT_EQUAL_UINT(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT) +#define UNITY_TEST_ASSERT_EQUAL_UINT8(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(UNITY_UINT8 )(expected), (UNITY_INT)(UNITY_UINT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8) +#define UNITY_TEST_ASSERT_EQUAL_UINT16(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(UNITY_UINT16)(expected), (UNITY_INT)(UNITY_UINT16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16) +#define UNITY_TEST_ASSERT_EQUAL_UINT32(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(UNITY_UINT32)(expected), (UNITY_INT)(UNITY_UINT32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32) +#define UNITY_TEST_ASSERT_EQUAL_HEX8(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(UNITY_INT8 )(expected), (UNITY_INT)(UNITY_INT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8) +#define UNITY_TEST_ASSERT_EQUAL_HEX16(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(UNITY_INT16)(expected), (UNITY_INT)(UNITY_INT16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16) +#define UNITY_TEST_ASSERT_EQUAL_HEX32(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(UNITY_INT32)(expected), (UNITY_INT)(UNITY_INT32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) +#define UNITY_TEST_ASSERT_EQUAL_CHAR(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(UNITY_INT8 )(expected), (UNITY_INT)(UNITY_INT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_CHAR) +#define UNITY_TEST_ASSERT_BITS(mask, expected, actual, line, message) UnityAssertBits((UNITY_INT)(mask), (UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line)) + +#define UNITY_TEST_ASSERT_NOT_EQUAL_INT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) +#define UNITY_TEST_ASSERT_NOT_EQUAL_INT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 )(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) +#define UNITY_TEST_ASSERT_NOT_EQUAL_INT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT16)(threshold), (UNITY_INT)(UNITY_INT16)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16) +#define UNITY_TEST_ASSERT_NOT_EQUAL_INT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT32)(threshold), (UNITY_INT)(UNITY_INT32)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32) +#define UNITY_TEST_ASSERT_NOT_EQUAL_UINT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT) +#define UNITY_TEST_ASSERT_NOT_EQUAL_UINT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8) +#define UNITY_TEST_ASSERT_NOT_EQUAL_UINT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16) +#define UNITY_TEST_ASSERT_NOT_EQUAL_UINT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32) +#define UNITY_TEST_ASSERT_NOT_EQUAL_HEX8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8) +#define UNITY_TEST_ASSERT_NOT_EQUAL_HEX16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16) +#define UNITY_TEST_ASSERT_NOT_EQUAL_HEX32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) +#define UNITY_TEST_ASSERT_NOT_EQUAL_CHAR(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 )(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_CHAR) + +#define UNITY_TEST_ASSERT_GREATER_THAN_INT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) +#define UNITY_TEST_ASSERT_GREATER_THAN_INT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 )(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) +#define UNITY_TEST_ASSERT_GREATER_THAN_INT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT16)(threshold), (UNITY_INT)(UNITY_INT16)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16) +#define UNITY_TEST_ASSERT_GREATER_THAN_INT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT32)(threshold), (UNITY_INT)(UNITY_INT32)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32) +#define UNITY_TEST_ASSERT_GREATER_THAN_UINT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT) +#define UNITY_TEST_ASSERT_GREATER_THAN_UINT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8) +#define UNITY_TEST_ASSERT_GREATER_THAN_UINT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16) +#define UNITY_TEST_ASSERT_GREATER_THAN_UINT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32) +#define UNITY_TEST_ASSERT_GREATER_THAN_HEX8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8) +#define UNITY_TEST_ASSERT_GREATER_THAN_HEX16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16) +#define UNITY_TEST_ASSERT_GREATER_THAN_HEX32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) +#define UNITY_TEST_ASSERT_GREATER_THAN_CHAR(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 )(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_CHAR) + +#define UNITY_TEST_ASSERT_SMALLER_THAN_INT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) +#define UNITY_TEST_ASSERT_SMALLER_THAN_INT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 )(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) +#define UNITY_TEST_ASSERT_SMALLER_THAN_INT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT16)(threshold), (UNITY_INT)(UNITY_INT16)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16) +#define UNITY_TEST_ASSERT_SMALLER_THAN_INT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT32)(threshold), (UNITY_INT)(UNITY_INT32)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32) +#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT) +#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8) +#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16) +#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32) +#define UNITY_TEST_ASSERT_SMALLER_THAN_HEX8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8) +#define UNITY_TEST_ASSERT_SMALLER_THAN_HEX16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16) +#define UNITY_TEST_ASSERT_SMALLER_THAN_HEX32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) +#define UNITY_TEST_ASSERT_SMALLER_THAN_CHAR(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 )(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_CHAR) + +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT) (threshold), (UNITY_INT) (actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 ) (threshold), (UNITY_INT)(UNITY_INT8 ) (actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT16) (threshold), (UNITY_INT)(UNITY_INT16) (actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT32) (threshold), (UNITY_INT)(UNITY_INT32) (actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT) (threshold), (UNITY_INT) (actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_CHAR(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 ) (threshold), (UNITY_INT)(UNITY_INT8 ) (actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_CHAR) + +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT) (threshold), (UNITY_INT) (actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 ) (actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT16)(threshold), (UNITY_INT)(UNITY_INT16) (actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT32)(threshold), (UNITY_INT)(UNITY_INT32) (actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT) (threshold), (UNITY_INT) (actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_CHAR(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 ) (actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_CHAR) + +#define UNITY_TEST_ASSERT_INT_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin( (delta), (UNITY_INT) (expected), (UNITY_INT) (actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) +#define UNITY_TEST_ASSERT_INT8_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT8 )(delta), (UNITY_INT)(UNITY_INT8 ) (expected), (UNITY_INT)(UNITY_INT8 ) (actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) +#define UNITY_TEST_ASSERT_INT16_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT16)(delta), (UNITY_INT)(UNITY_INT16) (expected), (UNITY_INT)(UNITY_INT16) (actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16) +#define UNITY_TEST_ASSERT_INT32_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT32)(delta), (UNITY_INT)(UNITY_INT32) (expected), (UNITY_INT)(UNITY_INT32) (actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32) +#define UNITY_TEST_ASSERT_UINT_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin( (delta), (UNITY_INT) (expected), (UNITY_INT) (actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT) +#define UNITY_TEST_ASSERT_UINT8_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT8 )(delta), (UNITY_INT)(UNITY_UINT)(UNITY_UINT8 )(expected), (UNITY_INT)(UNITY_UINT)(UNITY_UINT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8) +#define UNITY_TEST_ASSERT_UINT16_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT16)(delta), (UNITY_INT)(UNITY_UINT)(UNITY_UINT16)(expected), (UNITY_INT)(UNITY_UINT)(UNITY_UINT16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16) +#define UNITY_TEST_ASSERT_UINT32_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT32)(delta), (UNITY_INT)(UNITY_UINT)(UNITY_UINT32)(expected), (UNITY_INT)(UNITY_UINT)(UNITY_UINT32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32) +#define UNITY_TEST_ASSERT_HEX8_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT8 )(delta), (UNITY_INT)(UNITY_UINT)(UNITY_UINT8 )(expected), (UNITY_INT)(UNITY_UINT)(UNITY_UINT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8) +#define UNITY_TEST_ASSERT_HEX16_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT16)(delta), (UNITY_INT)(UNITY_UINT)(UNITY_UINT16)(expected), (UNITY_INT)(UNITY_UINT)(UNITY_UINT16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16) +#define UNITY_TEST_ASSERT_HEX32_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT32)(delta), (UNITY_INT)(UNITY_UINT)(UNITY_UINT32)(expected), (UNITY_INT)(UNITY_UINT)(UNITY_UINT32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) +#define UNITY_TEST_ASSERT_CHAR_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT8 )(delta), (UNITY_INT)(UNITY_INT8 ) (expected), (UNITY_INT)(UNITY_INT8 ) (actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_CHAR) + +#define UNITY_TEST_ASSERT_INT_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin( (delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_INT8_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT8 )(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_INT16_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT16)(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_INT32_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT32)(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_UINT_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin( (delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_UINT8_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin( (UNITY_UINT16)(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_UINT16_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT16)(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_UINT32_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT32)(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_HEX8_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT8 )(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_HEX16_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT16)(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_HEX32_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT32)(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_CHAR_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT8 )(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_CHAR, UNITY_ARRAY_TO_ARRAY) + + +#define UNITY_TEST_ASSERT_EQUAL_PTR(expected, actual, line, message) UnityAssertEqualNumber((UNITY_PTR_TO_INT)(expected), (UNITY_PTR_TO_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_POINTER) +#define UNITY_TEST_ASSERT_EQUAL_STRING(expected, actual, line, message) UnityAssertEqualString((const char*)(expected), (const char*)(actual), (message), (UNITY_LINE_TYPE)(line)) +#define UNITY_TEST_ASSERT_EQUAL_STRING_LEN(expected, actual, len, line, message) UnityAssertEqualStringLen((const char*)(expected), (const char*)(actual), (UNITY_UINT32)(len), (message), (UNITY_LINE_TYPE)(line)) +#define UNITY_TEST_ASSERT_EQUAL_MEMORY(expected, actual, len, line, message) UnityAssertEqualMemory((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(len), 1, (message), (UNITY_LINE_TYPE)(line), UNITY_ARRAY_TO_ARRAY) + +#define UNITY_TEST_ASSERT_EQUAL_INT_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_EQUAL_INT8_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_EQUAL_INT16_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_EQUAL_INT32_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_EQUAL_UINT_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_EQUAL_UINT8_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_EQUAL_UINT16_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_EQUAL_UINT32_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_EQUAL_HEX8_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_EQUAL_HEX16_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_EQUAL_HEX32_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_EQUAL_PTR_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_POINTER, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_EQUAL_STRING_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualStringArray((UNITY_INTERNAL_PTR)(expected), (const char**)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY(expected, actual, len, num_elements, line, message) UnityAssertEqualMemory((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(len), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_EQUAL_CHAR_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_CHAR, UNITY_ARRAY_TO_ARRAY) + +#define UNITY_TEST_ASSERT_EACH_EQUAL_INT(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT) (expected), (UNITY_INT_WIDTH / 8)), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT, UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_EACH_EQUAL_INT8(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT8 )(expected), 1), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8, UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_EACH_EQUAL_INT16(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT16 )(expected), 2), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16, UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_EACH_EQUAL_INT32(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT32 )(expected), 4), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32, UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_EACH_EQUAL_UINT(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT) (expected), (UNITY_INT_WIDTH / 8)), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT, UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_EACH_EQUAL_UINT8(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_UINT8 )(expected), 1), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8, UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_EACH_EQUAL_UINT16(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_UINT16)(expected), 2), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16, UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_EACH_EQUAL_UINT32(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_UINT32)(expected), 4), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32, UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_EACH_EQUAL_HEX8(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT8 )(expected), 1), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8, UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_EACH_EQUAL_HEX16(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT16 )(expected), 2), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16, UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_EACH_EQUAL_HEX32(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT32 )(expected), 4), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32, UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_EACH_EQUAL_PTR(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_PTR_TO_INT) (expected), (UNITY_POINTER_WIDTH / 8)), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_POINTER, UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_EACH_EQUAL_STRING(expected, actual, num_elements, line, message) UnityAssertEqualStringArray((UNITY_INTERNAL_PTR)(expected), (const char**)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_EACH_EQUAL_MEMORY(expected, actual, len, num_elements, line, message) UnityAssertEqualMemory((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(len), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_EACH_EQUAL_CHAR(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT8 )(expected), 1), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_CHAR, UNITY_ARRAY_TO_VAL) + +#ifdef UNITY_SUPPORT_64 +#define UNITY_TEST_ASSERT_EQUAL_INT64(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64) +#define UNITY_TEST_ASSERT_EQUAL_UINT64(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64) +#define UNITY_TEST_ASSERT_EQUAL_HEX64(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64) +#define UNITY_TEST_ASSERT_EQUAL_INT64_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_EQUAL_UINT64_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_EQUAL_HEX64_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_EACH_EQUAL_INT64(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT64)(expected), 8), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64, UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_EACH_EQUAL_UINT64(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_UINT64)(expected), 8), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64, UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_EACH_EQUAL_HEX64(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT64)(expected), 8), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64, UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_INT64_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((delta), (UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64) +#define UNITY_TEST_ASSERT_UINT64_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((delta), (UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64) +#define UNITY_TEST_ASSERT_HEX64_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((delta), (UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64) +#define UNITY_TEST_ASSERT_NOT_EQUAL_INT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64) +#define UNITY_TEST_ASSERT_NOT_EQUAL_UINT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64) +#define UNITY_TEST_ASSERT_NOT_EQUAL_HEX64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64) +#define UNITY_TEST_ASSERT_GREATER_THAN_INT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64) +#define UNITY_TEST_ASSERT_GREATER_THAN_UINT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64) +#define UNITY_TEST_ASSERT_GREATER_THAN_HEX64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64) +#define UNITY_TEST_ASSERT_SMALLER_THAN_INT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64) +#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64) +#define UNITY_TEST_ASSERT_SMALLER_THAN_HEX64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64) +#define UNITY_TEST_ASSERT_INT64_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT64)(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_UINT64_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT64)(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_HEX64_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT64)(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64, UNITY_ARRAY_TO_ARRAY) +#else +#define UNITY_TEST_ASSERT_EQUAL_INT64(expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_EQUAL_UINT64(expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_EQUAL_HEX64(expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_EQUAL_INT64_ARRAY(expected, actual, num_elements, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_EQUAL_UINT64_ARRAY(expected, actual, num_elements, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_EQUAL_HEX64_ARRAY(expected, actual, num_elements, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_INT64_WITHIN(delta, expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_UINT64_WITHIN(delta, expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_HEX64_WITHIN(delta, expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_GREATER_THAN_INT64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_GREATER_THAN_UINT64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_GREATER_THAN_HEX64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_SMALLER_THAN_INT64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_SMALLER_THAN_HEX64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_INT64_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_UINT64_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_HEX64_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#endif + +#ifdef UNITY_EXCLUDE_FLOAT +#define UNITY_TEST_ASSERT_FLOAT_WITHIN(delta, expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) +#define UNITY_TEST_ASSERT_EQUAL_FLOAT(expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) +#define UNITY_TEST_ASSERT_EQUAL_FLOAT_ARRAY(expected, actual, num_elements, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) +#define UNITY_TEST_ASSERT_EACH_EQUAL_FLOAT(expected, actual, num_elements, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) +#define UNITY_TEST_ASSERT_FLOAT_IS_INF(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) +#define UNITY_TEST_ASSERT_FLOAT_IS_NEG_INF(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) +#define UNITY_TEST_ASSERT_FLOAT_IS_NAN(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) +#define UNITY_TEST_ASSERT_FLOAT_IS_DETERMINATE(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) +#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_INF(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) +#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_NEG_INF(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) +#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_NAN(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) +#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) +#else +#define UNITY_TEST_ASSERT_FLOAT_WITHIN(delta, expected, actual, line, message) UnityAssertFloatsWithin((UNITY_FLOAT)(delta), (UNITY_FLOAT)(expected), (UNITY_FLOAT)(actual), (message), (UNITY_LINE_TYPE)(line)) +#define UNITY_TEST_ASSERT_EQUAL_FLOAT(expected, actual, line, message) UNITY_TEST_ASSERT_FLOAT_WITHIN((UNITY_FLOAT)(expected) * (UNITY_FLOAT)UNITY_FLOAT_PRECISION, (UNITY_FLOAT)(expected), (UNITY_FLOAT)(actual), (UNITY_LINE_TYPE)(line), (message)) +#define UNITY_TEST_ASSERT_EQUAL_FLOAT_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualFloatArray((UNITY_FLOAT*)(expected), (UNITY_FLOAT*)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_EACH_EQUAL_FLOAT(expected, actual, num_elements, line, message) UnityAssertEqualFloatArray(UnityFloatToPtr(expected), (UNITY_FLOAT*)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_FLOAT_IS_INF(actual, line, message) UnityAssertFloatSpecial((UNITY_FLOAT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_INF) +#define UNITY_TEST_ASSERT_FLOAT_IS_NEG_INF(actual, line, message) UnityAssertFloatSpecial((UNITY_FLOAT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NEG_INF) +#define UNITY_TEST_ASSERT_FLOAT_IS_NAN(actual, line, message) UnityAssertFloatSpecial((UNITY_FLOAT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NAN) +#define UNITY_TEST_ASSERT_FLOAT_IS_DETERMINATE(actual, line, message) UnityAssertFloatSpecial((UNITY_FLOAT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_DET) +#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_INF(actual, line, message) UnityAssertFloatSpecial((UNITY_FLOAT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_INF) +#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_NEG_INF(actual, line, message) UnityAssertFloatSpecial((UNITY_FLOAT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_NEG_INF) +#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_NAN(actual, line, message) UnityAssertFloatSpecial((UNITY_FLOAT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_NAN) +#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE(actual, line, message) UnityAssertFloatSpecial((UNITY_FLOAT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_DET) +#endif + +#ifdef UNITY_EXCLUDE_DOUBLE +#define UNITY_TEST_ASSERT_DOUBLE_WITHIN(delta, expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) +#define UNITY_TEST_ASSERT_EQUAL_DOUBLE(expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) +#define UNITY_TEST_ASSERT_EQUAL_DOUBLE_ARRAY(expected, actual, num_elements, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) +#define UNITY_TEST_ASSERT_EACH_EQUAL_DOUBLE(expected, actual, num_elements, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) +#define UNITY_TEST_ASSERT_DOUBLE_IS_INF(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) +#define UNITY_TEST_ASSERT_DOUBLE_IS_NEG_INF(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) +#define UNITY_TEST_ASSERT_DOUBLE_IS_NAN(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) +#define UNITY_TEST_ASSERT_DOUBLE_IS_DETERMINATE(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) +#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_INF(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) +#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) +#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NAN(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) +#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) +#else +#define UNITY_TEST_ASSERT_DOUBLE_WITHIN(delta, expected, actual, line, message) UnityAssertDoublesWithin((UNITY_DOUBLE)(delta), (UNITY_DOUBLE)(expected), (UNITY_DOUBLE)(actual), (message), (UNITY_LINE_TYPE)(line)) +#define UNITY_TEST_ASSERT_EQUAL_DOUBLE(expected, actual, line, message) UNITY_TEST_ASSERT_DOUBLE_WITHIN((UNITY_DOUBLE)(expected) * (UNITY_DOUBLE)UNITY_DOUBLE_PRECISION, (UNITY_DOUBLE)(expected), (UNITY_DOUBLE)(actual), (UNITY_LINE_TYPE)(line), (message)) +#define UNITY_TEST_ASSERT_EQUAL_DOUBLE_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualDoubleArray((UNITY_DOUBLE*)(expected), (UNITY_DOUBLE*)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_EACH_EQUAL_DOUBLE(expected, actual, num_elements, line, message) UnityAssertEqualDoubleArray(UnityDoubleToPtr(expected), (UNITY_DOUBLE*)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_DOUBLE_IS_INF(actual, line, message) UnityAssertDoubleSpecial((UNITY_DOUBLE)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_INF) +#define UNITY_TEST_ASSERT_DOUBLE_IS_NEG_INF(actual, line, message) UnityAssertDoubleSpecial((UNITY_DOUBLE)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NEG_INF) +#define UNITY_TEST_ASSERT_DOUBLE_IS_NAN(actual, line, message) UnityAssertDoubleSpecial((UNITY_DOUBLE)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NAN) +#define UNITY_TEST_ASSERT_DOUBLE_IS_DETERMINATE(actual, line, message) UnityAssertDoubleSpecial((UNITY_DOUBLE)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_DET) +#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_INF(actual, line, message) UnityAssertDoubleSpecial((UNITY_DOUBLE)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_INF) +#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF(actual, line, message) UnityAssertDoubleSpecial((UNITY_DOUBLE)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_NEG_INF) +#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NAN(actual, line, message) UnityAssertDoubleSpecial((UNITY_DOUBLE)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_NAN) +#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE(actual, line, message) UnityAssertDoubleSpecial((UNITY_DOUBLE)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_DET) +#endif + +/* End of UNITY_INTERNALS_H */ +#endif diff --git a/c/hello-world/test_hello_world.c b/c/hello-world/test_hello_world.c new file mode 100644 index 0000000..b9aa642 --- /dev/null +++ b/c/hello-world/test_hello_world.c @@ -0,0 +1,35 @@ +// Include the test framework. +#include "test-framework/unity.h" + +// Include the header file with the declarations of the functions you create. +#include "hello_world.h" + +// Runs before every test. +void setUp(void) +{ +} + +// Runs after every test. +void tearDown(void) +{ +} + +// Defines a single test. +static void test_say_hi(void) +{ + // Check if the 'hello()' function returns "Hello, World!" + // This test is expected to fail after first downloading this exercise. + // To make this test pass, fix the 'hello()' function definition in the + // source file hello_world.c. + TEST_ASSERT_EQUAL_STRING("Hello, World!", hello()); +} + +// Runs the test(s) +int main(void) +{ + UNITY_BEGIN(); + + RUN_TEST(test_say_hi); + + return UNITY_END(); +} diff --git a/c/hello-world/tests.out b/c/hello-world/tests.out new file mode 100755 index 0000000..6fa7cb8 Binary files /dev/null and b/c/hello-world/tests.out differ diff --git a/dart/hello-world/.exercism/config.json b/dart/hello-world/.exercism/config.json new file mode 100644 index 0000000..ef2014e --- /dev/null +++ b/dart/hello-world/.exercism/config.json @@ -0,0 +1,26 @@ +{ + "authors": [ + "SuperPaintman" + ], + "contributors": [ + "rafaelalvessa", + "Stargator" + ], + "files": { + "solution": [ + "lib/hello_world.dart" + ], + "test": [ + "test/hello_world_test.dart" + ], + "example": [ + ".meta/lib/example.dart" + ], + "invalidator": [ + "pubspec.yaml" + ] + }, + "blurb": "Exercism's classic introductory exercise. Just say \"Hello, World!\".", + "source": "This is an exercise to introduce users to using Exercism", + "source_url": "https://en.wikipedia.org/wiki/%22Hello,_world!%22_program" +} diff --git a/dart/hello-world/.exercism/metadata.json b/dart/hello-world/.exercism/metadata.json new file mode 100644 index 0000000..36d5162 --- /dev/null +++ b/dart/hello-world/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"dart","exercise":"hello-world","id":"3416a5e62e344dd3ab25a1455c84721e","url":"https://exercism.org/tracks/dart/exercises/hello-world","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/dart/hello-world/HELP.md b/dart/hello-world/HELP.md new file mode 100644 index 0000000..def3079 --- /dev/null +++ b/dart/hello-world/HELP.md @@ -0,0 +1,38 @@ +# Help + +## Running the tests + +To run the tests: + +```sh +$ dart test +``` + +## Submitting your solution + +You can submit your solution using the `exercism submit lib/hello_world.dart` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Dart track's documentation](https://exercism.org/docs/tracks/dart) +- The [Dart track's programming category on the forum](https://forum.exercism.org/c/programming/dart) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +To get help if you're having trouble, you can use one of the following resources: + +- [Dart API Documentation](https://api.dart.dev/) +- [Dart Gitter Chat](https://gitter.im/dart-lang/home) +- [Community Information](https://www.dart.dev/community) +- [/r/dartlang](https://www.reddit.com/r/dartlang) is the Dart subreddit. +- [StackOverflow](https://stackoverflow.com/questions/tagged/dart) can be used to search for your problem and see if it has been answered already. You can also ask and answer questions. \ No newline at end of file diff --git a/dart/hello-world/README.md b/dart/hello-world/README.md new file mode 100644 index 0000000..f3cd4db --- /dev/null +++ b/dart/hello-world/README.md @@ -0,0 +1,36 @@ +# Hello World + +Welcome to Hello World on Exercism's Dart Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Instructions + +The classical introductory exercise. +Just say "Hello, World!". + +["Hello, World!"][hello-world] is the traditional first program for beginning programming in a new language or environment. + +The objectives are simple: + +- Modify the provided code so that it produces the string "Hello, World!". +- Run the test suite and make sure that it succeeds. +- Submit your solution and check it at the website. + +If everything goes well, you will be ready to fetch your first real exercise. + +[hello-world]: https://en.wikipedia.org/wiki/%22Hello,_world!%22_program + +## Source + +### Created by + +- @SuperPaintman + +### Contributed to by + +- @rafaelalvessa +- @Stargator + +### Based on + +This is an exercise to introduce users to using Exercism - https://en.wikipedia.org/wiki/%22Hello,_world!%22_program \ No newline at end of file diff --git a/dart/hello-world/analysis_options.yaml b/dart/hello-world/analysis_options.yaml new file mode 100644 index 0000000..f35e80c --- /dev/null +++ b/dart/hello-world/analysis_options.yaml @@ -0,0 +1,20 @@ +analyzer: + exclude: + - lib/hello_world.dart + strong-mode: + implicit-casts: false + implicit-dynamic: false + errors: + unused_element: error + unused_import: error + unused_local_variable: error + dead_code: error + +linter: + rules: + # Error Rules + - avoid_relative_lib_imports + - avoid_types_as_parameter_names + - literal_only_boolean_expressions + - no_adjacent_strings_in_list + - valid_regexps diff --git a/dart/hello-world/lib/hello_world.dart b/dart/hello-world/lib/hello_world.dart new file mode 100644 index 0000000..2282dc6 --- /dev/null +++ b/dart/hello-world/lib/hello_world.dart @@ -0,0 +1,5 @@ +class HelloWorld { + String hello() { + return "Hello, World!"; + } +} diff --git a/dart/hello-world/pubspec.yaml b/dart/hello-world/pubspec.yaml new file mode 100644 index 0000000..a920c35 --- /dev/null +++ b/dart/hello-world/pubspec.yaml @@ -0,0 +1,5 @@ +name: 'hello_world' +environment: + sdk: '>=3.2.0 <4.0.0' +dev_dependencies: + test: '<2.0.0' diff --git a/dart/hello-world/test/hello_world_test.dart b/dart/hello-world/test/hello_world_test.dart new file mode 100644 index 0000000..529037b --- /dev/null +++ b/dart/hello-world/test/hello_world_test.dart @@ -0,0 +1,8 @@ +import 'package:hello_world/hello_world.dart'; +import 'package:test/test.dart'; + +void main() { + test('Say Hi!', () { + expect(HelloWorld().hello(), equals('Hello, World!')); + }); +} diff --git a/dart/two-fer/.dart_tool/package_config.json b/dart/two-fer/.dart_tool/package_config.json new file mode 100644 index 0000000..90fbb90 --- /dev/null +++ b/dart/two-fer/.dart_tool/package_config.json @@ -0,0 +1,298 @@ +{ + "configVersion": 2, + "packages": [ + { + "name": "_fe_analyzer_shared", + "rootUri": "file:///home/sanctus/.pub-cache/hosted/pub.dev/_fe_analyzer_shared-100.0.0", + "packageUri": "lib/", + "languageVersion": "3.11" + }, + { + "name": "analyzer", + "rootUri": "file:///home/sanctus/.pub-cache/hosted/pub.dev/analyzer-13.0.0", + "packageUri": "lib/", + "languageVersion": "3.9" + }, + { + "name": "args", + "rootUri": "file:///home/sanctus/.pub-cache/hosted/pub.dev/args-2.7.0", + "packageUri": "lib/", + "languageVersion": "3.3" + }, + { + "name": "async", + "rootUri": "file:///home/sanctus/.pub-cache/hosted/pub.dev/async-2.13.1", + "packageUri": "lib/", + "languageVersion": "3.4" + }, + { + "name": "boolean_selector", + "rootUri": "file:///home/sanctus/.pub-cache/hosted/pub.dev/boolean_selector-2.1.2", + "packageUri": "lib/", + "languageVersion": "3.1" + }, + { + "name": "cli_config", + "rootUri": "file:///home/sanctus/.pub-cache/hosted/pub.dev/cli_config-0.2.0", + "packageUri": "lib/", + "languageVersion": "3.0" + }, + { + "name": "collection", + "rootUri": "file:///home/sanctus/.pub-cache/hosted/pub.dev/collection-1.19.1", + "packageUri": "lib/", + "languageVersion": "3.4" + }, + { + "name": "convert", + "rootUri": "file:///home/sanctus/.pub-cache/hosted/pub.dev/convert-3.1.2", + "packageUri": "lib/", + "languageVersion": "3.4" + }, + { + "name": "coverage", + "rootUri": "file:///home/sanctus/.pub-cache/hosted/pub.dev/coverage-1.15.0", + "packageUri": "lib/", + "languageVersion": "3.4" + }, + { + "name": "crypto", + "rootUri": "file:///home/sanctus/.pub-cache/hosted/pub.dev/crypto-3.0.7", + "packageUri": "lib/", + "languageVersion": "3.4" + }, + { + "name": "file", + "rootUri": "file:///home/sanctus/.pub-cache/hosted/pub.dev/file-7.0.1", + "packageUri": "lib/", + "languageVersion": "3.0" + }, + { + "name": "frontend_server_client", + "rootUri": "file:///home/sanctus/.pub-cache/hosted/pub.dev/frontend_server_client-4.0.0", + "packageUri": "lib/", + "languageVersion": "3.0" + }, + { + "name": "glob", + "rootUri": "file:///home/sanctus/.pub-cache/hosted/pub.dev/glob-2.1.3", + "packageUri": "lib/", + "languageVersion": "3.3" + }, + { + "name": "http_multi_server", + "rootUri": "file:///home/sanctus/.pub-cache/hosted/pub.dev/http_multi_server-3.2.2", + "packageUri": "lib/", + "languageVersion": "3.2" + }, + { + "name": "http_parser", + "rootUri": "file:///home/sanctus/.pub-cache/hosted/pub.dev/http_parser-4.1.2", + "packageUri": "lib/", + "languageVersion": "3.4" + }, + { + "name": "io", + "rootUri": "file:///home/sanctus/.pub-cache/hosted/pub.dev/io-1.0.5", + "packageUri": "lib/", + "languageVersion": "3.4" + }, + { + "name": "logging", + "rootUri": "file:///home/sanctus/.pub-cache/hosted/pub.dev/logging-1.3.0", + "packageUri": "lib/", + "languageVersion": "3.4" + }, + { + "name": "matcher", + "rootUri": "file:///home/sanctus/.pub-cache/hosted/pub.dev/matcher-0.12.20", + "packageUri": "lib/", + "languageVersion": "3.10" + }, + { + "name": "meta", + "rootUri": "file:///home/sanctus/.pub-cache/hosted/pub.dev/meta-1.18.2", + "packageUri": "lib/", + "languageVersion": "3.5" + }, + { + "name": "mime", + "rootUri": "file:///home/sanctus/.pub-cache/hosted/pub.dev/mime-2.0.0", + "packageUri": "lib/", + "languageVersion": "3.2" + }, + { + "name": "node_preamble", + "rootUri": "file:///home/sanctus/.pub-cache/hosted/pub.dev/node_preamble-2.0.2", + "packageUri": "lib/", + "languageVersion": "2.12" + }, + { + "name": "package_config", + "rootUri": "file:///home/sanctus/.pub-cache/hosted/pub.dev/package_config-2.2.0", + "packageUri": "lib/", + "languageVersion": "3.4" + }, + { + "name": "path", + "rootUri": "file:///home/sanctus/.pub-cache/hosted/pub.dev/path-1.9.1", + "packageUri": "lib/", + "languageVersion": "3.4" + }, + { + "name": "pool", + "rootUri": "file:///home/sanctus/.pub-cache/hosted/pub.dev/pool-1.5.2", + "packageUri": "lib/", + "languageVersion": "3.4" + }, + { + "name": "pub_semver", + "rootUri": "file:///home/sanctus/.pub-cache/hosted/pub.dev/pub_semver-2.2.0", + "packageUri": "lib/", + "languageVersion": "3.4" + }, + { + "name": "shelf", + "rootUri": "file:///home/sanctus/.pub-cache/hosted/pub.dev/shelf-1.4.2", + "packageUri": "lib/", + "languageVersion": "3.4" + }, + { + "name": "shelf_packages_handler", + "rootUri": "file:///home/sanctus/.pub-cache/hosted/pub.dev/shelf_packages_handler-3.0.2", + "packageUri": "lib/", + "languageVersion": "2.17" + }, + { + "name": "shelf_static", + "rootUri": "file:///home/sanctus/.pub-cache/hosted/pub.dev/shelf_static-1.1.3", + "packageUri": "lib/", + "languageVersion": "3.3" + }, + { + "name": "shelf_web_socket", + "rootUri": "file:///home/sanctus/.pub-cache/hosted/pub.dev/shelf_web_socket-3.0.0", + "packageUri": "lib/", + "languageVersion": "3.5" + }, + { + "name": "source_map_stack_trace", + "rootUri": "file:///home/sanctus/.pub-cache/hosted/pub.dev/source_map_stack_trace-2.1.2", + "packageUri": "lib/", + "languageVersion": "3.3" + }, + { + "name": "source_maps", + "rootUri": "file:///home/sanctus/.pub-cache/hosted/pub.dev/source_maps-0.10.13", + "packageUri": "lib/", + "languageVersion": "3.3" + }, + { + "name": "source_span", + "rootUri": "file:///home/sanctus/.pub-cache/hosted/pub.dev/source_span-1.10.2", + "packageUri": "lib/", + "languageVersion": "3.1" + }, + { + "name": "stack_trace", + "rootUri": "file:///home/sanctus/.pub-cache/hosted/pub.dev/stack_trace-1.12.1", + "packageUri": "lib/", + "languageVersion": "3.4" + }, + { + "name": "stream_channel", + "rootUri": "file:///home/sanctus/.pub-cache/hosted/pub.dev/stream_channel-2.1.4", + "packageUri": "lib/", + "languageVersion": "3.3" + }, + { + "name": "string_scanner", + "rootUri": "file:///home/sanctus/.pub-cache/hosted/pub.dev/string_scanner-1.4.1", + "packageUri": "lib/", + "languageVersion": "3.1" + }, + { + "name": "term_glyph", + "rootUri": "file:///home/sanctus/.pub-cache/hosted/pub.dev/term_glyph-1.2.2", + "packageUri": "lib/", + "languageVersion": "3.1" + }, + { + "name": "test", + "rootUri": "file:///home/sanctus/.pub-cache/hosted/pub.dev/test-1.31.1", + "packageUri": "lib/", + "languageVersion": "3.10" + }, + { + "name": "test_api", + "rootUri": "file:///home/sanctus/.pub-cache/hosted/pub.dev/test_api-0.7.12", + "packageUri": "lib/", + "languageVersion": "3.10" + }, + { + "name": "test_core", + "rootUri": "file:///home/sanctus/.pub-cache/hosted/pub.dev/test_core-0.6.18", + "packageUri": "lib/", + "languageVersion": "3.10" + }, + { + "name": "typed_data", + "rootUri": "file:///home/sanctus/.pub-cache/hosted/pub.dev/typed_data-1.4.0", + "packageUri": "lib/", + "languageVersion": "3.5" + }, + { + "name": "vm_service", + "rootUri": "file:///home/sanctus/.pub-cache/hosted/pub.dev/vm_service-15.1.0", + "packageUri": "lib/", + "languageVersion": "3.5" + }, + { + "name": "watcher", + "rootUri": "file:///home/sanctus/.pub-cache/hosted/pub.dev/watcher-1.2.1", + "packageUri": "lib/", + "languageVersion": "3.4" + }, + { + "name": "web", + "rootUri": "file:///home/sanctus/.pub-cache/hosted/pub.dev/web-1.1.1", + "packageUri": "lib/", + "languageVersion": "3.4" + }, + { + "name": "web_socket", + "rootUri": "file:///home/sanctus/.pub-cache/hosted/pub.dev/web_socket-1.0.1", + "packageUri": "lib/", + "languageVersion": "3.4" + }, + { + "name": "web_socket_channel", + "rootUri": "file:///home/sanctus/.pub-cache/hosted/pub.dev/web_socket_channel-3.0.3", + "packageUri": "lib/", + "languageVersion": "3.3" + }, + { + "name": "webkit_inspection_protocol", + "rootUri": "file:///home/sanctus/.pub-cache/hosted/pub.dev/webkit_inspection_protocol-1.2.1", + "packageUri": "lib/", + "languageVersion": "3.0" + }, + { + "name": "yaml", + "rootUri": "file:///home/sanctus/.pub-cache/hosted/pub.dev/yaml-3.1.3", + "packageUri": "lib/", + "languageVersion": "3.4" + }, + { + "name": "two_fer", + "rootUri": "../", + "packageUri": "lib/", + "languageVersion": "3.2" + } + ], + "generator": "pub", + "generatorVersion": "3.11.0", + "flutterRoot": "file:///home/sanctus/flutter", + "flutterVersion": "3.41.2", + "pubCache": "file:///home/sanctus/.pub-cache" +} diff --git a/dart/two-fer/.dart_tool/package_graph.json b/dart/two-fer/.dart_tool/package_graph.json new file mode 100644 index 0000000..7979844 --- /dev/null +++ b/dart/two-fer/.dart_tool/package_graph.json @@ -0,0 +1,442 @@ +{ + "roots": [ + "two_fer" + ], + "packages": [ + { + "name": "two_fer", + "version": "0.0.0", + "dependencies": [], + "devDependencies": [ + "test" + ] + }, + { + "name": "test", + "version": "1.31.1", + "dependencies": [ + "analyzer", + "async", + "boolean_selector", + "collection", + "coverage", + "http_multi_server", + "io", + "matcher", + "node_preamble", + "package_config", + "path", + "pool", + "shelf", + "shelf_packages_handler", + "shelf_static", + "shelf_web_socket", + "source_span", + "stack_trace", + "stream_channel", + "test_api", + "test_core", + "typed_data", + "web_socket_channel", + "webkit_inspection_protocol", + "yaml" + ] + }, + { + "name": "test_core", + "version": "0.6.18", + "dependencies": [ + "analyzer", + "args", + "async", + "boolean_selector", + "collection", + "coverage", + "frontend_server_client", + "glob", + "io", + "meta", + "package_config", + "path", + "pool", + "source_map_stack_trace", + "source_maps", + "source_span", + "stack_trace", + "stream_channel", + "test_api", + "vm_service", + "yaml" + ] + }, + { + "name": "test_api", + "version": "0.7.12", + "dependencies": [ + "async", + "boolean_selector", + "collection", + "meta", + "source_span", + "stack_trace", + "stream_channel", + "string_scanner", + "term_glyph" + ] + }, + { + "name": "coverage", + "version": "1.15.0", + "dependencies": [ + "args", + "cli_config", + "glob", + "logging", + "meta", + "package_config", + "path", + "source_maps", + "stack_trace", + "vm_service", + "yaml" + ] + }, + { + "name": "yaml", + "version": "3.1.3", + "dependencies": [ + "collection", + "source_span", + "string_scanner" + ] + }, + { + "name": "cli_config", + "version": "0.2.0", + "dependencies": [ + "args", + "yaml" + ] + }, + { + "name": "glob", + "version": "2.1.3", + "dependencies": [ + "async", + "collection", + "file", + "path", + "string_scanner" + ] + }, + { + "name": "frontend_server_client", + "version": "4.0.0", + "dependencies": [ + "async", + "path" + ] + }, + { + "name": "shelf_packages_handler", + "version": "3.0.2", + "dependencies": [ + "path", + "shelf", + "shelf_static" + ] + }, + { + "name": "pool", + "version": "1.5.2", + "dependencies": [ + "async", + "stack_trace" + ] + }, + { + "name": "node_preamble", + "version": "2.0.2", + "dependencies": [] + }, + { + "name": "boolean_selector", + "version": "2.1.2", + "dependencies": [ + "source_span", + "string_scanner" + ] + }, + { + "name": "source_map_stack_trace", + "version": "2.1.2", + "dependencies": [ + "path", + "source_maps", + "stack_trace" + ] + }, + { + "name": "term_glyph", + "version": "1.2.2", + "dependencies": [] + }, + { + "name": "typed_data", + "version": "1.4.0", + "dependencies": [ + "collection" + ] + }, + { + "name": "source_maps", + "version": "0.10.13", + "dependencies": [ + "source_span" + ] + }, + { + "name": "string_scanner", + "version": "1.4.1", + "dependencies": [ + "source_span" + ] + }, + { + "name": "file", + "version": "7.0.1", + "dependencies": [ + "meta", + "path" + ] + }, + { + "name": "path", + "version": "1.9.1", + "dependencies": [] + }, + { + "name": "webkit_inspection_protocol", + "version": "1.2.1", + "dependencies": [ + "logging" + ] + }, + { + "name": "stream_channel", + "version": "2.1.4", + "dependencies": [ + "async" + ] + }, + { + "name": "stack_trace", + "version": "1.12.1", + "dependencies": [ + "path" + ] + }, + { + "name": "shelf_static", + "version": "1.1.3", + "dependencies": [ + "convert", + "http_parser", + "mime", + "path", + "shelf" + ] + }, + { + "name": "package_config", + "version": "2.2.0", + "dependencies": [ + "path" + ] + }, + { + "name": "io", + "version": "1.0.5", + "dependencies": [ + "meta", + "path", + "string_scanner" + ] + }, + { + "name": "http_multi_server", + "version": "3.2.2", + "dependencies": [ + "async" + ] + }, + { + "name": "meta", + "version": "1.18.2", + "dependencies": [] + }, + { + "name": "matcher", + "version": "0.12.20", + "dependencies": [ + "async", + "meta", + "stack_trace", + "term_glyph", + "test_api" + ] + }, + { + "name": "async", + "version": "2.13.1", + "dependencies": [ + "collection", + "meta" + ] + }, + { + "name": "args", + "version": "2.7.0", + "dependencies": [] + }, + { + "name": "http_parser", + "version": "4.1.2", + "dependencies": [ + "collection", + "source_span", + "string_scanner", + "typed_data" + ] + }, + { + "name": "collection", + "version": "1.19.1", + "dependencies": [] + }, + { + "name": "convert", + "version": "3.1.2", + "dependencies": [ + "typed_data" + ] + }, + { + "name": "logging", + "version": "1.3.0", + "dependencies": [] + }, + { + "name": "source_span", + "version": "1.10.2", + "dependencies": [ + "collection", + "path", + "term_glyph" + ] + }, + { + "name": "shelf_web_socket", + "version": "3.0.0", + "dependencies": [ + "shelf", + "stream_channel", + "web_socket_channel" + ] + }, + { + "name": "mime", + "version": "2.0.0", + "dependencies": [] + }, + { + "name": "shelf", + "version": "1.4.2", + "dependencies": [ + "async", + "collection", + "http_parser", + "path", + "stack_trace", + "stream_channel" + ] + }, + { + "name": "web_socket_channel", + "version": "3.0.3", + "dependencies": [ + "async", + "crypto", + "stream_channel", + "web", + "web_socket" + ] + }, + { + "name": "web_socket", + "version": "1.0.1", + "dependencies": [ + "web" + ] + }, + { + "name": "web", + "version": "1.1.1", + "dependencies": [] + }, + { + "name": "crypto", + "version": "3.0.7", + "dependencies": [ + "typed_data" + ] + }, + { + "name": "vm_service", + "version": "15.1.0", + "dependencies": [] + }, + { + "name": "analyzer", + "version": "13.0.0", + "dependencies": [ + "_fe_analyzer_shared", + "collection", + "convert", + "crypto", + "glob", + "meta", + "package_config", + "path", + "pub_semver", + "source_span", + "watcher", + "yaml" + ] + }, + { + "name": "_fe_analyzer_shared", + "version": "100.0.0", + "dependencies": [ + "meta", + "source_span" + ] + }, + { + "name": "pub_semver", + "version": "2.2.0", + "dependencies": [ + "collection" + ] + }, + { + "name": "watcher", + "version": "1.2.1", + "dependencies": [ + "async", + "path" + ] + } + ], + "configVersion": 1 +} \ No newline at end of file diff --git a/dart/two-fer/.dart_tool/pub/bin/test/test.dart-3.11.0.snapshot b/dart/two-fer/.dart_tool/pub/bin/test/test.dart-3.11.0.snapshot new file mode 100644 index 0000000..6b2e5e1 Binary files /dev/null and b/dart/two-fer/.dart_tool/pub/bin/test/test.dart-3.11.0.snapshot differ diff --git a/dart/two-fer/.dart_tool/test/incremental_kernel.Ly9AZGFydD0zLjI= b/dart/two-fer/.dart_tool/test/incremental_kernel.Ly9AZGFydD0zLjI= new file mode 100644 index 0000000..2eff150 Binary files /dev/null and b/dart/two-fer/.dart_tool/test/incremental_kernel.Ly9AZGFydD0zLjI= differ diff --git a/dart/two-fer/.exercism/config.json b/dart/two-fer/.exercism/config.json new file mode 100644 index 0000000..502f5c8 --- /dev/null +++ b/dart/two-fer/.exercism/config.json @@ -0,0 +1,25 @@ +{ + "authors": [ + "amscotti" + ], + "contributors": [ + "Stargator", + "kytrinyx" + ], + "files": { + "solution": [ + "lib/two_fer.dart" + ], + "test": [ + "test/two_fer_test.dart" + ], + "example": [ + ".meta/lib/example.dart" + ], + "invalidator": [ + "pubspec.yaml" + ] + }, + "blurb": "Create a sentence of the form \"One for X, one for me.\".", + "source_url": "https://github.com/exercism/problem-specifications/issues/757" +} diff --git a/dart/two-fer/.exercism/metadata.json b/dart/two-fer/.exercism/metadata.json new file mode 100644 index 0000000..b9849a3 --- /dev/null +++ b/dart/two-fer/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"dart","exercise":"two-fer","id":"1a2c804be07e4a0f96162c56700f7827","url":"https://exercism.org/tracks/dart/exercises/two-fer","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/dart/two-fer/HELP.md b/dart/two-fer/HELP.md new file mode 100644 index 0000000..25fd26b --- /dev/null +++ b/dart/two-fer/HELP.md @@ -0,0 +1,61 @@ +# Help + +## Running the tests + +Install dependencies. + +```sh +dart pub get +``` + +Run the tests. + +```sh +dart test +``` + +For more detailed per-test output, use the expanded reporter. + +```sh +dart test -r expanded +``` + +Most exercises have multiple tests, with all but the first skipped by default. +To work through tests one at a time, change `skip: true` to `skip: false` on each test as you go. + +Alternatively, run all tests at once without editing the file. + +```sh +dart test --run-skipped +``` + +All tests are run by the online test runner on submission, including skipped ones. + +## Submitting your solution + +You can submit your solution using the `exercism submit lib/two_fer.dart` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Dart track's documentation](https://exercism.org/docs/tracks/dart) +- The [Dart track's programming category on the forum](https://forum.exercism.org/c/programming/dart) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +To get help if you're having trouble, you can use one of the following resources: + +- [Dart API Documentation](https://api.dart.dev/) +- [Dart Gitter Chat](https://gitter.im/dart-lang/home) +- [Community Information](https://www.dart.dev/community) +- [/r/dartlang](https://www.reddit.com/r/dartlang) is the Dart subreddit. +- [StackOverflow](https://stackoverflow.com/questions/tagged/dart) can be used to search for your problem and see if it has been answered already. You can also ask and answer questions. \ No newline at end of file diff --git a/dart/two-fer/README.md b/dart/two-fer/README.md new file mode 100644 index 0000000..72a53f2 --- /dev/null +++ b/dart/two-fer/README.md @@ -0,0 +1,53 @@ +# Two Fer + +Welcome to Two Fer on Exercism's Dart Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Introduction + +In some English accents, when you say "two for" quickly, it sounds like "two fer". +Two-for-one is a way of saying that if you buy one, you also get one for free. +So the phrase "two-fer" often implies a two-for-one offer. + +Imagine a bakery that has a holiday offer where you can buy two cookies for the price of one ("two-fer one!"). +You take the offer and (very generously) decide to give the extra cookie to someone else in the queue. + +## Instructions + +Your task is to determine what you will say as you give away the extra cookie. + +If you know the person's name (e.g. if they're named Do-yun), then you will say: + +```text +One for Do-yun, one for me. +``` + +If you don't know the person's name, you will say _you_ instead. + +```text +One for you, one for me. +``` + +Here are some examples: + +| Name | Dialogue | +| :----- | :-------------------------- | +| Alice | One for Alice, one for me. | +| Bohdan | One for Bohdan, one for me. | +| | One for you, one for me. | +| Zaphod | One for Zaphod, one for me. | + +## Source + +### Created by + +- @amscotti + +### Contributed to by + +- @Stargator +- @kytrinyx + +### Based on + +https://github.com/exercism/problem-specifications/issues/757 \ No newline at end of file diff --git a/dart/two-fer/analysis_options.yaml b/dart/two-fer/analysis_options.yaml new file mode 100644 index 0000000..c06363d --- /dev/null +++ b/dart/two-fer/analysis_options.yaml @@ -0,0 +1,18 @@ +analyzer: + strong-mode: + implicit-casts: false + implicit-dynamic: false + errors: + unused_element: error + unused_import: error + unused_local_variable: error + dead_code: error + +linter: + rules: + # Error Rules + - avoid_relative_lib_imports + - avoid_types_as_parameter_names + - literal_only_boolean_expressions + - no_adjacent_strings_in_list + - valid_regexps diff --git a/dart/two-fer/lib/two_fer.dart b/dart/two-fer/lib/two_fer.dart new file mode 100644 index 0000000..199db3b --- /dev/null +++ b/dart/two-fer/lib/two_fer.dart @@ -0,0 +1,6 @@ +String twoFer([String? name]) { + if (name == null) { + name = 'you'; + } + return 'One for $name, one for me.'; +} diff --git a/dart/two-fer/pubspec.lock b/dart/two-fer/pubspec.lock new file mode 100644 index 0000000..bdb448f --- /dev/null +++ b/dart/two-fer/pubspec.lock @@ -0,0 +1,381 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + sha256: cd6add6f846f35fb79f3c315296703c1a24f3cfd7f4739d91a74961c1c7e9f1b + url: "https://pub.dev" + source: hosted + version: "100.0.0" + analyzer: + dependency: transitive + description: + name: analyzer + sha256: "6ba98576948803398b69e3a444df24eacdbe12ed699c7014e120ea38552debbf" + url: "https://pub.dev" + source: hosted + version: "13.0.0" + args: + dependency: transitive + description: + name: args + sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 + url: "https://pub.dev" + source: hosted + version: "2.7.0" + async: + dependency: transitive + description: + name: async + sha256: e2eb0491ba5ddb6177742d2da23904574082139b07c1e33b8503b9f46f3e1a37 + url: "https://pub.dev" + source: hosted + version: "2.13.1" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + cli_config: + dependency: transitive + description: + name: cli_config + sha256: ac20a183a07002b700f0c25e61b7ee46b23c309d76ab7b7640a028f18e4d99ec + url: "https://pub.dev" + source: hosted + version: "0.2.0" + collection: + dependency: transitive + description: + name: collection + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" + url: "https://pub.dev" + source: hosted + version: "1.19.1" + convert: + dependency: transitive + description: + name: convert + sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 + url: "https://pub.dev" + source: hosted + version: "3.1.2" + coverage: + dependency: transitive + description: + name: coverage + sha256: "5da775aa218eaf2151c721b16c01c7676fbfdd99cebba2bf64e8b807a28ff94d" + url: "https://pub.dev" + source: hosted + version: "1.15.0" + crypto: + dependency: transitive + description: + name: crypto + sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf + url: "https://pub.dev" + source: hosted + version: "3.0.7" + file: + dependency: transitive + description: + name: file + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 + url: "https://pub.dev" + source: hosted + version: "7.0.1" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 + url: "https://pub.dev" + source: hosted + version: "4.0.0" + glob: + dependency: transitive + description: + name: glob + sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de + url: "https://pub.dev" + source: hosted + version: "2.1.3" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8 + url: "https://pub.dev" + source: hosted + version: "3.2.2" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" + url: "https://pub.dev" + source: hosted + version: "4.1.2" + io: + dependency: transitive + description: + name: io + sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b + url: "https://pub.dev" + source: hosted + version: "1.0.5" + logging: + dependency: transitive + description: + name: logging + sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 + url: "https://pub.dev" + source: hosted + version: "1.3.0" + matcher: + dependency: transitive + description: + name: matcher + sha256: "31bd099b47c10cd1aeb55146a2d46ce0277630ecef3f7dae54ad7873f36696cd" + url: "https://pub.dev" + source: hosted + version: "0.12.20" + meta: + dependency: transitive + description: + name: meta + sha256: df0c643f44ad098eb37988027a8e2b2b5a031fd3977f06bbfd3a76637e8df739 + url: "https://pub.dev" + source: hosted + version: "1.18.2" + mime: + dependency: transitive + description: + name: mime + sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" + url: "https://pub.dev" + source: hosted + version: "2.0.0" + node_preamble: + dependency: transitive + description: + name: node_preamble + sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db" + url: "https://pub.dev" + source: hosted + version: "2.0.2" + package_config: + dependency: transitive + description: + name: package_config + sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc + url: "https://pub.dev" + source: hosted + version: "2.2.0" + path: + dependency: transitive + description: + name: path + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" + url: "https://pub.dev" + source: hosted + version: "1.9.1" + pool: + dependency: transitive + description: + name: pool + sha256: "978783255c543aa3586a1b3c21f6e9d720eb315376a915872c61ef8b5c20177d" + url: "https://pub.dev" + source: hosted + version: "1.5.2" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + shelf: + dependency: transitive + description: + name: shelf + sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12 + url: "https://pub.dev" + source: hosted + version: "1.4.2" + shelf_packages_handler: + dependency: transitive + description: + name: shelf_packages_handler + sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + shelf_static: + dependency: transitive + description: + name: shelf_static + sha256: c87c3875f91262785dade62d135760c2c69cb217ac759485334c5857ad89f6e3 + url: "https://pub.dev" + source: hosted + version: "1.1.3" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + sha256: "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925" + url: "https://pub.dev" + source: hosted + version: "3.0.0" + source_map_stack_trace: + dependency: transitive + description: + name: source_map_stack_trace + sha256: c0713a43e323c3302c2abe2a1cc89aa057a387101ebd280371d6a6c9fa68516b + url: "https://pub.dev" + source: hosted + version: "2.1.2" + source_maps: + dependency: transitive + description: + name: source_maps + sha256: "190222579a448b03896e0ca6eca5998fa810fda630c1d65e2f78b3f638f54812" + url: "https://pub.dev" + source: hosted + version: "0.10.13" + source_span: + dependency: transitive + description: + name: source_span + sha256: "56a02f1f4cd1a2d96303c0144c93bd6d909eea6bee6bf5a0e0b685edbd4c47ab" + url: "https://pub.dev" + source: hosted + version: "1.10.2" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" + url: "https://pub.dev" + source: hosted + version: "1.12.1" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" + url: "https://pub.dev" + source: hosted + version: "1.4.1" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" + url: "https://pub.dev" + source: hosted + version: "1.2.2" + test: + dependency: "direct dev" + description: + name: test + sha256: ca578dc12bb8b2f40b67b7d3bd2fac4f31c01a6ff7130a14e2597b919934507f + url: "https://pub.dev" + source: hosted + version: "1.31.1" + test_api: + dependency: transitive + description: + name: test_api + sha256: "2a122cbe059f8b610d3a5415f42e255b6c17b1f21eee1d960f31080237fb4f11" + url: "https://pub.dev" + source: hosted + version: "0.7.12" + test_core: + dependency: transitive + description: + name: test_core + sha256: d2e98ec12998368dc59ddd47ab709f2cd55acd6b66dc7db764455a44082f4bc5 + url: "https://pub.dev" + source: hosted + version: "0.6.18" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 + url: "https://pub.dev" + source: hosted + version: "1.4.0" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: "046d3928e16fa4dc46e8350415661755ab759d9fc97fc21b5ab295f71e4f0499" + url: "https://pub.dev" + source: hosted + version: "15.1.0" + watcher: + dependency: transitive + description: + name: watcher + sha256: "1398c9f081a753f9226febe8900fce8f7d0a67163334e1c94a2438339d79d635" + url: "https://pub.dev" + source: hosted + version: "1.2.1" + web: + dependency: transitive + description: + name: web + sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" + url: "https://pub.dev" + source: hosted + version: "1.1.1" + web_socket: + dependency: transitive + description: + name: web_socket + sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c" + url: "https://pub.dev" + source: hosted + version: "1.0.1" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8 + url: "https://pub.dev" + source: hosted + version: "3.0.3" + webkit_inspection_protocol: + dependency: transitive + description: + name: webkit_inspection_protocol + sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572" + url: "https://pub.dev" + source: hosted + version: "1.2.1" + yaml: + dependency: transitive + description: + name: yaml + sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce + url: "https://pub.dev" + source: hosted + version: "3.1.3" +sdks: + dart: ">=3.11.0 <4.0.0" diff --git a/dart/two-fer/pubspec.yaml b/dart/two-fer/pubspec.yaml new file mode 100644 index 0000000..5fa43cc --- /dev/null +++ b/dart/two-fer/pubspec.yaml @@ -0,0 +1,5 @@ +name: 'two_fer' +environment: + sdk: '>=3.2.0 <4.0.0' +dev_dependencies: + test: '<2.0.0' diff --git a/dart/two-fer/test/two_fer_test.dart b/dart/two-fer/test/two_fer_test.dart new file mode 100644 index 0000000..f9dc4e4 --- /dev/null +++ b/dart/two-fer/test/two_fer_test.dart @@ -0,0 +1,21 @@ +import 'package:test/test.dart'; +import 'package:two_fer/two_fer.dart'; + +void main() { + group('TwoFer', () { + test('no name given', () { + final result = twoFer(); + expect(result, equals('One for you, one for me.')); + }, skip: false); + + test('a name given', () { + final result = twoFer('Alice'); + expect(result, equals('One for Alice, one for me.')); + }, skip: true); + + test('another name given', () { + final result = twoFer('Bob'); + expect(result, equals('One for Bob, one for me.')); + }, skip: true); + }); +} diff --git a/go/annalyns-infiltration/.exercism/config.json b/go/annalyns-infiltration/.exercism/config.json new file mode 100644 index 0000000..e35a1f3 --- /dev/null +++ b/go/annalyns-infiltration/.exercism/config.json @@ -0,0 +1,26 @@ +{ + "authors": [ + "oanaOM" + ], + "files": { + "solution": [ + "annalyns_infiltration.go" + ], + "test": [ + "annalyns_infiltration_test.go" + ], + "exemplar": [ + ".meta/exemplar.go" + ], + "invalidator": [ + "go.mod" + ] + }, + "forked_from": [ + "csharp/annalyns-infiltration" + ], + "blurb": "Learn about booleans by helping Annalyn free her best friend.", + "custom": { + "taskIdsEnabled": true + } +} diff --git a/go/annalyns-infiltration/.exercism/metadata.json b/go/annalyns-infiltration/.exercism/metadata.json new file mode 100644 index 0000000..45cd708 --- /dev/null +++ b/go/annalyns-infiltration/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"go","exercise":"annalyns-infiltration","id":"7a1da8b9a1844d21a3cc71aca4ee5f0b","url":"https://exercism.org/tracks/go/exercises/annalyns-infiltration","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/go/annalyns-infiltration/HELP.md b/go/annalyns-infiltration/HELP.md new file mode 100644 index 0000000..457a3c1 --- /dev/null +++ b/go/annalyns-infiltration/HELP.md @@ -0,0 +1,41 @@ +# Help + +## Running the tests + +To run the tests run the command `go test` from within the exercise directory. + +If the test suite contains benchmarks, you can run these with the `--bench` and `--benchmem` +flags: + + go test -v --bench . --benchmem + +Keep in mind that each reviewer will run benchmarks on a different machine, with +different specs, so the results from these benchmark tests may vary. + +## Submitting your solution + +You can submit your solution using the `exercism submit annalyns_infiltration.go` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Go track's documentation](https://exercism.org/docs/tracks/go) +- The [Go track's programming category on the forum](https://forum.exercism.org/c/programming/go) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +To get help if you're having trouble, you can use one of the following resources: + +- [How to Write Go Code](https://golang.org/doc/code.html) +- [Effective Go](https://golang.org/doc/effective_go.html) +- [Go Resources](http://golang.org/help) +- [StackOverflow](http://stackoverflow.com/questions/tagged/go) \ No newline at end of file diff --git a/go/annalyns-infiltration/HINTS.md b/go/annalyns-infiltration/HINTS.md new file mode 100644 index 0000000..f027e14 --- /dev/null +++ b/go/annalyns-infiltration/HINTS.md @@ -0,0 +1,23 @@ +# Hints + +## General + +- There are three [boolean operators][logical operators] to work with boolean values. +- Multiple operators can be combined in a single expression. + +## 1. Check if a fast attack can be made + +- The logical NOT operator (`!`) can be placed before an expression to negate its value. + +## 2. Check if the group can be spied upon + +- Logical operators are typically used to evaluate whether two or more expressions are true or not true. + +## 3. Check if the prisoner can be signaled + +- Logical operators execute in the order of their precedence (from highest to lowest): `!`, `&&`, `||`. +- For more details check out the Operator Precedence section on the [official golang documentation][operators] and the [truth table][truth table]. + +[logical operators]: https://golang.org/ref/spec#Logical_operators +[operators]: https://golang.org/ref/spec#Operators +[truth table]: https://www.digitalocean.com/community/tutorials/understanding-boolean-logic-in-go \ No newline at end of file diff --git a/go/annalyns-infiltration/README.md b/go/annalyns-infiltration/README.md new file mode 100644 index 0000000..30ce258 --- /dev/null +++ b/go/annalyns-infiltration/README.md @@ -0,0 +1,111 @@ +# Annalyn's Infiltration + +Welcome to Annalyn's Infiltration on Exercism's Go Track. +If you need help running the tests or submitting your code, check out `HELP.md`. +If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :) + +## Introduction + +Booleans in Go are represented by the predeclared boolean type `bool`, which values can be either `true` or `false`. +It's a defined type. + +```go +var closed bool // boolean variable 'closed' implicitly initialized with 'false' +speeding := true // boolean variable 'speeding' initialized with 'true' +hasError := false // boolean variable 'hasError' initialized with 'false' +``` + +Go supports three logical operators that can evaluate expressions down to Boolean values, returning either `true` or `false`. + +| Operator | What it means | +| ----------- | --------------------------------------------- | +| `&&` (and) | It is true if both statements are true. | +| `\|\|` (or) | It is true if at least one statement is true. | +| `!` (not) | It is true only if the statement is false. | + +## Instructions + +In this exercise, you'll be implementing the quest logic for a new RPG game a friend is developing. +The game's main character is Annalyn, a brave girl with a fierce and loyal pet dog. +Unfortunately, disaster strikes, as her best friend was kidnapped while searching for berries in the forest. +Annalyn will try to find and free her best friend, optionally taking her dog with her on this quest. + +After some time spent following her best friend's trail, she finds the camp in which her best friend is imprisoned. +It turns out there are two kidnappers: a mighty knight and a cunning archer. + +Having found the kidnappers, Annalyn considers which of the following actions she can engage in: + +- _Fast attack_: a fast attack can be made if the knight is sleeping, as it takes time for him to get his armor on, so he will be vulnerable. +- _Spy_: the group can be spied upon if at least one of them is awake. + Otherwise, spying is a waste of time. +- _Signal prisoner_: the prisoner can be signaled using bird sounds if the prisoner is awake and the archer is sleeping, as archers are trained in bird signaling so they could intercept the message. +- _Free prisoner_: Annalyn can try sneaking into the camp to free the prisoner. + This is a risky thing to do and can only succeed in one of two ways: + - If Annalyn has her pet dog with her she can rescue the prisoner if the archer is asleep. + The knight is scared of the dog and the archer will not have time to get ready before Annalyn and the prisoner can escape. + - If Annalyn does not have her dog then she and the prisoner must be very sneaky! + Annalyn can free the prisoner if the prisoner is awake and the knight and archer are both sleeping, but if the prisoner is sleeping they can't be rescued: the prisoner would be startled by Annalyn's sudden appearance and wake up the knight and archer. + +You have four tasks: to implement the logic for determining if the above actions are available based on the state of the three characters found in the forest and whether Annalyn's pet dog is present or not. + +## 1. Check if a fast attack can be made + +Define the `CanFastAttack()` function that takes a boolean value that indicates if the knight is awake. +This function returns `true` if a fast attack can be made based on the state of the knight. +Otherwise, returns `false`: + +```go +var knightIsAwake = true +fmt.Println(CanFastAttack(knightIsAwake)) +// Output: false +``` + +## 2. Check if the group can be spied upon + +Define the `CanSpy()` function that takes three boolean values, indicating if the knight, archer and the prisoner, respectively, are awake. +The function returns `true` if the group can be spied upon, based on the state of the three characters. +Otherwise, returns `false`: + +```go +var knightIsAwake = false +var archerIsAwake = true +var prisonerIsAwake = false +fmt.Println(CanSpy(knightIsAwake, archerIsAwake, prisonerIsAwake)) +// Output: true +``` + +## 3. Check if the prisoner can be signaled + +Define the `CanSignalPrisoner()` function that takes two boolean values, indicating if the archer and the prisoner, respectively, are awake. +The function returns `true` if the prisoner can be signaled, based on the state of the two characters. +Otherwise, returns `false`: + +```go +var archerIsAwake = false +var prisonerIsAwake = true +fmt.Println(CanSignalPrisoner(archerIsAwake, prisonerIsAwake)) +// Output: true +``` + +## 4. Check if the prisoner can be freed + +Define the `CanFreePrisoner()` function that takes four boolean values. +The first three parameters indicate if the knight, archer and the prisoner, respectively, are awake. +The last parameter indicates if Annalyn's pet dog is present. +The function returns `true` if the prisoner can be freed based on the state of the three characters and Annalyn's pet dog presence. +Otherwise, it returns `false`: + +```go +var knightIsAwake = false +var archerIsAwake = true +var prisonerIsAwake = false +var petDogIsPresent = false +fmt.Println(CanFreePrisoner(knightIsAwake, archerIsAwake, prisonerIsAwake, petDogIsPresent)) +// Output: false +``` + +## Source + +### Created by + +- @oanaOM \ No newline at end of file diff --git a/go/annalyns-infiltration/annalyns_infiltration.go b/go/annalyns-infiltration/annalyns_infiltration.go new file mode 100644 index 0000000..a881164 --- /dev/null +++ b/go/annalyns-infiltration/annalyns_infiltration.go @@ -0,0 +1,22 @@ +package annalyn + +// CanFastAttack can be executed only when the knight is sleeping. +func CanFastAttack(knightIsAwake bool) bool { + return !knightIsAwake +} + +// CanSpy can be executed if at least one of the characters is awake. +func CanSpy(knightIsAwake, archerIsAwake, prisonerIsAwake bool) bool { + return knightIsAwake || archerIsAwake || prisonerIsAwake +} + +// CanSignalPrisoner can be executed if the prisoner is awake and the archer is sleeping. +func CanSignalPrisoner(archerIsAwake, prisonerIsAwake bool) bool { + return !archerIsAwake && prisonerIsAwake +} + +// CanFreePrisoner can be executed if the prisoner is awake and the other 2 characters are asleep +// or if Annalyn's pet dog is with her and the archer is sleeping. +func CanFreePrisoner(knightIsAwake, archerIsAwake, prisonerIsAwake, petDogIsPresent bool) bool { + return (prisonerIsAwake && (!knightIsAwake && !archerIsAwake)) || (!archerIsAwake && petDogIsPresent) +} diff --git a/go/annalyns-infiltration/annalyns_infiltration_test.go b/go/annalyns-infiltration/annalyns_infiltration_test.go new file mode 100644 index 0000000..f322e6c --- /dev/null +++ b/go/annalyns-infiltration/annalyns_infiltration_test.go @@ -0,0 +1,286 @@ +package annalyn + +import "testing" + +type charactersState struct { + desc string + knightIsAwake bool + archerIsAwake bool + prisonerIsAwake bool + dogIsPresent bool + expected bool +} + +func TestCanFastAttack(t *testing.T) { + tests := []charactersState{ + { + desc: "Knight is awake", + knightIsAwake: true, + expected: false, + }, + { + desc: "Knight is sleeping", + knightIsAwake: false, + expected: true, + }, + } + for _, tc := range tests { + t.Run(tc.desc, func(t *testing.T) { + if got := CanFastAttack(tc.knightIsAwake); got != tc.expected { + t.Errorf("CanFastAttack(%v) = %v; want %v", tc.knightIsAwake, got, tc.expected) + } + }) + } +} + +func TestCanSpy(t *testing.T) { + tests := []charactersState{ + { + desc: "All characters are sleeping", + knightIsAwake: false, + archerIsAwake: false, + prisonerIsAwake: false, + expected: false, + }, + { + desc: "Knight is awake, archer and prisoner are sleeping", + knightIsAwake: true, + archerIsAwake: false, + prisonerIsAwake: false, + expected: true, + }, + { + desc: "Knight and archer are awake, prisoner is sleeping", + knightIsAwake: true, + archerIsAwake: true, + prisonerIsAwake: false, + expected: true, + }, + { + desc: "Knight and prisoner are awake, archer is sleeping", + knightIsAwake: true, + archerIsAwake: false, + prisonerIsAwake: true, + expected: true, + }, + { + desc: "Archer is awake, knight and prisoner are sleeping", + knightIsAwake: false, + archerIsAwake: true, + prisonerIsAwake: false, + expected: true, + }, + { + desc: "Archer and prisoner are awake, knight is sleeping", + knightIsAwake: false, + archerIsAwake: true, + prisonerIsAwake: true, + expected: true, + }, + { + desc: "Prisoner is awake, knight and archer are sleeping", + knightIsAwake: false, + archerIsAwake: false, + prisonerIsAwake: true, + expected: true, + }, + { + desc: "All characters are awake", + knightIsAwake: true, + archerIsAwake: true, + prisonerIsAwake: true, + expected: true, + }, + } + for _, tc := range tests { + t.Run(tc.desc, func(t *testing.T) { + if got := CanSpy(tc.knightIsAwake, tc.archerIsAwake, tc.prisonerIsAwake); got != tc.expected { + t.Errorf("CanSpy(%v, %v, %v) = %v; want %v", tc.knightIsAwake, tc.archerIsAwake, tc.prisonerIsAwake, got, tc.expected) + } + }) + } +} + +func TestCanSignalPrisoner(t *testing.T) { + tests := []charactersState{ + { + desc: "All characters are sleeping", + archerIsAwake: false, + prisonerIsAwake: false, + expected: false, + }, + { + desc: "Archer is sleeping, prisoner is awake", + archerIsAwake: false, + prisonerIsAwake: true, + expected: true, + }, + { + desc: "Archer is awake, prisoner is sleeping", + archerIsAwake: true, + prisonerIsAwake: false, + expected: false, + }, + { + desc: "All characters are awake", + archerIsAwake: true, + prisonerIsAwake: true, + expected: false, + }, + } + for _, tc := range tests { + t.Run(tc.desc, func(t *testing.T) { + if got := CanSignalPrisoner(tc.archerIsAwake, tc.prisonerIsAwake); got != tc.expected { + t.Errorf("CanSignalPrisoner(%v, %v) = %v; want %v", tc.archerIsAwake, tc.prisonerIsAwake, got, tc.expected) + } + }) + } +} + +func TestCanFreePrisoner(t *testing.T) { + tests := []charactersState{ + { + desc: "All characters are sleeping. Dog is not present.", + knightIsAwake: false, + archerIsAwake: false, + prisonerIsAwake: false, + dogIsPresent: false, + expected: false, + }, + { + desc: "All characters are sleeping. Dog is present.", + knightIsAwake: false, + archerIsAwake: false, + prisonerIsAwake: false, + dogIsPresent: true, + expected: true, + }, + { + desc: "Knight and archer are sleeping. Prisoner is awake. Dog is not present.", + knightIsAwake: false, + archerIsAwake: false, + prisonerIsAwake: true, + dogIsPresent: false, + expected: true, + }, + { + desc: "Knight and archer are sleeping. Prisoner is awake. Dog is present.", + knightIsAwake: false, + archerIsAwake: false, + prisonerIsAwake: true, + dogIsPresent: true, + expected: true, + }, + { + desc: "Knight is sleeping. Archer is awake. Prisoner is sleeping. Dog is not present.", + knightIsAwake: false, + archerIsAwake: true, + prisonerIsAwake: false, + dogIsPresent: false, + expected: false, + }, + { + desc: "Knight is sleeping. Archer is awake. Prisoner is sleeping. Dog is present.", + knightIsAwake: false, + archerIsAwake: true, + prisonerIsAwake: false, + dogIsPresent: true, + expected: false, + }, + { + desc: "Knight is sleeping. Archer is awake. Prisoner is awake. Dog is not present.", + knightIsAwake: false, + archerIsAwake: true, + prisonerIsAwake: true, + dogIsPresent: false, + expected: false, + }, + { + desc: "Knight is sleeping. Archer is awake. Prisoner is awake. Dog is present.", + knightIsAwake: false, + archerIsAwake: true, + prisonerIsAwake: true, + dogIsPresent: true, + expected: false, + }, + { + desc: "Knight is awake. Archer is sleeping. Prisoner is sleeping. Dog is not present.", + knightIsAwake: true, + archerIsAwake: false, + prisonerIsAwake: false, + dogIsPresent: false, + expected: false, + }, + { + desc: "Knight is awake. Archer is sleeping. Prisoner is sleeping. Dog is present.", + knightIsAwake: true, + archerIsAwake: false, + prisonerIsAwake: false, + dogIsPresent: true, + expected: true, + }, + { + desc: "Knight is awake. Archer is sleeping. Prisoner is awake. Dog is not present", + knightIsAwake: true, + archerIsAwake: false, + prisonerIsAwake: true, + dogIsPresent: false, + expected: false, + }, + { + desc: "Knight is awake. Archer is sleeping. Prisoner is awake. Dog is present", + knightIsAwake: true, + archerIsAwake: false, + prisonerIsAwake: true, + dogIsPresent: true, + expected: true, + }, + { + desc: "Knight and archer are awake. Prisoner is sleeping. Dog is not present", + knightIsAwake: true, + archerIsAwake: true, + prisonerIsAwake: false, + dogIsPresent: false, + expected: false, + }, + { + desc: "Knight and archer are awake. Prisoner is sleeping. Dog is present", + knightIsAwake: true, + archerIsAwake: true, + prisonerIsAwake: false, + dogIsPresent: true, + expected: false, + }, + { + desc: "Knight and archer are awake. Prisoner is awake. Dog is not present", + knightIsAwake: true, + archerIsAwake: true, + prisonerIsAwake: true, + dogIsPresent: false, + expected: false, + }, + { + desc: "Knight and archer are awake. Prisoner is awake. Dog is present", + knightIsAwake: true, + archerIsAwake: true, + prisonerIsAwake: true, + dogIsPresent: true, + expected: false, + }, + { + desc: "Everyone is sleeping. Dog is not present", + knightIsAwake: false, + archerIsAwake: false, + prisonerIsAwake: false, + dogIsPresent: false, + expected: false, + }, + } + for _, tc := range tests { + t.Run(tc.desc, func(t *testing.T) { + if got := CanFreePrisoner(tc.knightIsAwake, tc.archerIsAwake, tc.prisonerIsAwake, tc.dogIsPresent); got != tc.expected { + t.Errorf("CanFreePrisoner(%v,%v,%v,%v) = %v; want %v", tc.knightIsAwake, tc.archerIsAwake, tc.prisonerIsAwake, tc.dogIsPresent, got, tc.expected) + } + }) + } +} diff --git a/go/annalyns-infiltration/go.mod b/go/annalyns-infiltration/go.mod new file mode 100644 index 0000000..03f8415 --- /dev/null +++ b/go/annalyns-infiltration/go.mod @@ -0,0 +1,3 @@ +module annalyn + +go 1.26 diff --git a/go/cars-assemble/.exercism/config.json b/go/cars-assemble/.exercism/config.json new file mode 100644 index 0000000..d74d833 --- /dev/null +++ b/go/cars-assemble/.exercism/config.json @@ -0,0 +1,28 @@ +{ + "authors": [ + "DavyJ0nes", + "kahgoh" + ], + "contributors": [ + "tehsphinx", + "andrerfcsantos" + ], + "files": { + "solution": [ + "cars_assemble.go" + ], + "test": [ + "cars_assemble_test.go" + ], + "exemplar": [ + ".meta/exemplar.go" + ], + "invalidator": [ + "go.mod" + ] + }, + "blurb": "Learn about numbers and type conversion by analyzing an assembly line in a car factory.", + "custom": { + "taskIdsEnabled": true + } +} diff --git a/go/cars-assemble/.exercism/metadata.json b/go/cars-assemble/.exercism/metadata.json new file mode 100644 index 0000000..f5ffd5f --- /dev/null +++ b/go/cars-assemble/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"go","exercise":"cars-assemble","id":"4fa36f30c78743439e2f50df93aeb7bb","url":"https://exercism.org/tracks/go/exercises/cars-assemble","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/go/cars-assemble/HELP.md b/go/cars-assemble/HELP.md new file mode 100644 index 0000000..70cf69f --- /dev/null +++ b/go/cars-assemble/HELP.md @@ -0,0 +1,41 @@ +# Help + +## Running the tests + +To run the tests run the command `go test` from within the exercise directory. + +If the test suite contains benchmarks, you can run these with the `--bench` and `--benchmem` +flags: + + go test -v --bench . --benchmem + +Keep in mind that each reviewer will run benchmarks on a different machine, with +different specs, so the results from these benchmark tests may vary. + +## Submitting your solution + +You can submit your solution using the `exercism submit cars_assemble.go` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Go track's documentation](https://exercism.org/docs/tracks/go) +- The [Go track's programming category on the forum](https://forum.exercism.org/c/programming/go) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +To get help if you're having trouble, you can use one of the following resources: + +- [How to Write Go Code](https://golang.org/doc/code.html) +- [Effective Go](https://golang.org/doc/effective_go.html) +- [Go Resources](http://golang.org/help) +- [StackOverflow](http://stackoverflow.com/questions/tagged/go) \ No newline at end of file diff --git a/go/cars-assemble/HINTS.md b/go/cars-assemble/HINTS.md new file mode 100644 index 0000000..fb2f5cd --- /dev/null +++ b/go/cars-assemble/HINTS.md @@ -0,0 +1,32 @@ +# Hints + +## General + +- To learn more about types in Go, check [Tour of Go: Basic Types][basic types]. +- To learn more about type conversions in Go, check [Tour of Go: Type Conversions][type conversions]. + +## 1. Calculate the number of working cars produced per hour + +- The percentage (passed as an argument) is a number between 0-100. To make this percentage a bit easier to work with, start by dividing it by 100. +- To compute the number of cars produced successfully, multiply the percentage (divided by 100) by the number of cars produced. +- When multiplying two numbers together, they both need to be of the same type. + Use [type conversions][type conversions] if needed. + +## 2. Calculate the number of working cars produced per minute + +- Start by calculating the production of successful cars per hour. + For this, you can use the `CalculateProductionRatePerHour` function you made from the previous step. +- Knowing the production per hour of cars, you can get the production per minute by dividing the production per hour by 60 (the number of minutes in an hour). +- Remember to cast the result to an `int`. + +## 3. Calculate the cost of production + +- Start by working out how many groups of 10 cars there are. + You can do this by dividing the number of cars by 10. +- Then work out how many cars are remaining (the [modulo operator][modulo operator] is useful for this). +- To arrive at the cost, multiply the number of groups by the cost to produce 10 cars and then multiply the number of cars remaining by the cost to produce each individual car. + Then sum the results of the multiplication together. + +[basic types]: https://tour.golang.org/basics/11 +[type conversions]: https://tour.golang.org/basics/13 +[modulo operator]: https://golangbyexamples.com/remainder-modulus-go-golang/ \ No newline at end of file diff --git a/go/cars-assemble/README.md b/go/cars-assemble/README.md new file mode 100644 index 0000000..c7da4f0 --- /dev/null +++ b/go/cars-assemble/README.md @@ -0,0 +1,138 @@ +# Cars Assemble + +Welcome to Cars Assemble on Exercism's Go Track. +If you need help running the tests or submitting your code, check out `HELP.md`. +If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :) + +## Introduction + +## Numbers + +Go contains basic numeric types that can represent sets of either integer or floating-point values. +There are different types depending on the size of value you require and the architecture of the computer where the application is running (e.g. 32-bit and 64-bit). + +For the sake of this exercise you will only be dealing with: + +- `int`: e.g. `0`, `255`, `2147483647`. + A signed integer that is at least 32 bits in size (value range of: -2147483648 through 2147483647). + But this will depend on the systems architecture. + Most modern computers are 64 bit, therefore `int` will be 64 bits in size (value rate of: -9223372036854775808 through 9223372036854775807). + +- `float64`: e.g. `0.0`, `3.14`. + Contains the set of all 64-bit floating-point numbers. + +- `uint`: e.g. `0`, `255`. + An unsigned integer that is the same size as `int` (value range of: 0 through 4294967295 for 32 bits and 0 through 18446744073709551615 for 64 bits) + +Numbers can be converted to other numeric types through Type Conversion. + +## Arithmetic Operators + +Go supports many standard arithmetic operators: + +| Operator | Example | +| -------- | -------------- | +| `+` | `4 + 6 == 10` | +| `-` | `15 - 10 == 5` | +| `*` | `2 * 3 == 6` | +| `/` | `13 / 3 == 4` | +| `%` | `13 % 3 == 1` | + +For integer division, the remainder is dropped (e.g. `5 / 2 == 2`). + +Go has shorthand assignment for the operators above (e.g. `a += 5` is short for `a = a + 5`). +Go also supports the increment and decrement statements `++` and `--` (e.g. `a++`). + +## Converting between types + +Converting between types is done via a function with the name of the type to convert to. +For example: + +```go +var x int = 42 // x has type int +f := float64(x) // f has type float64 (ie. 42.0) +var y float64 = 11.9 // y has type float64 +i := int(y) // i has type int (ie. 11) +``` + +## Arithmetic operations on different types + +In many languages you can perform arithmetic operations on different types of variables, but in Go this gives an error. +For example: + +```go +var x int = 42 + +// this line produces an error +value := float32(2.0) * x // invalid operation: mismatched types float32 and int + +// you must convert int type to float32 before performing arithmetic operation +value := float32(2.0) * float32(x) +``` + +## Instructions + +In this exercise you'll be writing code to analyze the production in a car factory. + +## 1. Calculate the number of working cars produced per hour + +The cars are produced on an assembly line. +The assembly line has a certain speed, that can be changed. +The faster the assembly line speed is, the more cars are produced. +However, changing the speed of the assembly line also changes the number of cars that are produced successfully, that is cars without any errors in their production. + +Implement a function that takes in the number of cars produced per hour and the success rate and calculates the number of successful cars made per hour. +The success rate is given as a percentage, from `0` to `100`: + +```go +CalculateWorkingCarsPerHour(1547, 90) +// => 1392.3 +``` + +**Note:** the return value should be a `float64`. + +## 2. Calculate the number of working cars produced per minute + +Implement a function that takes in the number of cars produced per hour and the success rate and calculates how many cars are successfully produced each minute: + +```go +CalculateWorkingCarsPerMinute(1105, 90) +// => 16 +``` + +**Note:** the return value should be an `int`. + +## 3. Calculate the cost of production + +Each car normally costs $10,000 to produce individually, regardless of whether it is successful or not. +But with a bit of planning, 10 cars can be produced together for $95,000. + +For example, 37 cars can be produced in the following way: +37 = 3 x groups of ten + 7 individual cars + +So the cost for 37 cars is: +3\*95,000+7\*10,000=355,000 + +Implement the function `CalculateCost` that calculates the cost of producing a number of cars, regardless of whether they are successful: + +```go +CalculateCost(37) +// => 355000 + +CalculateCost(21) +// => 200000 +``` + +**Note:** the return value should be an `uint`. + +## Source + +### Created by + +- @DavyJ0nes +- @kahgoh + +### Contributed to by + +- @tehsphinx +- @andrerfcsantos \ No newline at end of file diff --git a/go/cars-assemble/cars_assemble.go b/go/cars-assemble/cars_assemble.go new file mode 100644 index 0000000..7c2cf62 --- /dev/null +++ b/go/cars-assemble/cars_assemble.go @@ -0,0 +1,19 @@ +package cars + +// CalculateWorkingCarsPerHour calculates how many working cars are +// produced by the assembly line every hour. +func CalculateWorkingCarsPerHour(productionRate int, successRate float64) float64 { + return float64(productionRate) * successRate/100.0 +} + +// CalculateWorkingCarsPerMinute calculates how many working cars are +// produced by the assembly line every minute. +func CalculateWorkingCarsPerMinute(productionRate int, successRate float64) int { + return int(float64(productionRate)/60 * successRate/100) +} + +// CalculateCost works out the cost of producing the given number of cars. +func CalculateCost(carsCount int) uint { + var numberOfBundles uint = uint(carsCount/10) + return (numberOfBundles*95000) + (uint(carsCount)-(numberOfBundles*10))*10000 +} diff --git a/go/cars-assemble/cars_assemble_test.go b/go/cars-assemble/cars_assemble_test.go new file mode 100644 index 0000000..37382f5 --- /dev/null +++ b/go/cars-assemble/cars_assemble_test.go @@ -0,0 +1,197 @@ +package cars + +import ( + "math" + "testing" +) + +const floatEqualityThreshold = 1e-9 + +func floatingPointEquals(got, want float64) bool { + absoluteDifferenceBelowThreshold := math.Abs(got-want) <= floatEqualityThreshold + relativeDifferenceBelowThreshold := math.Abs(got-want)/(math.Abs(got)+math.Abs(want)) <= floatEqualityThreshold + return absoluteDifferenceBelowThreshold || relativeDifferenceBelowThreshold +} + +func TestCalculateWorkingCarsPerHour(t *testing.T) { + tests := []struct { + name string + productionRate int + successRate float64 + want float64 + }{ + { + name: "calculate working cars per hour for production rate 0", + productionRate: 0, + successRate: 100, + want: 0.0, + }, + { + name: "calculate working cars per hour for 100% success rate", + productionRate: 221, + successRate: 100, + want: 221.0, + }, + { + name: "calculate working cars per hour for 80% success rate", + productionRate: 426, + successRate: 80, + want: 340.8, + }, + { + name: "calculate working cars per hour for 20.5% success rate", + productionRate: 6824, + successRate: 20.5, + want: 1398.92, + }, + { + name: "calculate working cars per hour for 0% success rate", + productionRate: 8000, + successRate: 0, + want: 0, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + got := CalculateWorkingCarsPerHour(tc.productionRate, tc.successRate) + if !floatingPointEquals(got, tc.want) { + t.Errorf( + "CalculateWorkingCarsPerHour(%d, %f) = %f, want %f", + tc.productionRate, + tc.successRate, + got, + tc.want, + ) + } + }) + } +} + +func TestCalculateWorkingCarsPerMinute(t *testing.T) { + tests := []struct { + name string + productionRate int + successRate float64 + want int + }{ + { + name: "calculate working cars per minute for production rate 0", + productionRate: 0, + successRate: 100, + want: 0, + }, + { + name: "calculate working cars per minute for 100% success rate", + productionRate: 221, + successRate: 100, + want: 3, + }, + { + name: "calculate working cars per minute for 80% success rate", + productionRate: 426, + successRate: 80, + want: 5, + }, + { + name: "calculate working cars per minute for 20.5% success rate", + productionRate: 6824, + successRate: 20.5, + want: 23, + }, + { + name: "calculate working cars per minute for 0% success rate", + productionRate: 8000, + successRate: 0, + want: 0, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + got := CalculateWorkingCarsPerMinute(tc.productionRate, tc.successRate) + if got != tc.want { + t.Errorf( + "CalculateWorkingCarsPerMinute(%d, %f) = %d, want %d", + tc.productionRate, + tc.successRate, + got, + tc.want, + ) + } + }) + } +} + +func TestCalculateCost(t *testing.T) { + tests := []struct { + name string + carsCount int + want uint + }{ + { + name: "calculate cost to produce 0 cars", + carsCount: 0, + want: 0, + }, + { + name: "calculate the cost of materials to produce 1 car", + carsCount: 1, + want: 10000, + }, + { + name: "calculate cost to produce 2 cars", + carsCount: 2, + want: 20000, + }, + { + name: "calculate cost to produce 9 cars", + carsCount: 9, + want: 90000, + }, + { + name: "calculate cost to produce 10 cars", + carsCount: 10, + want: 95000, + }, + { + name: "calculate cost to produce 100 cars", + carsCount: 100, + want: 950000, + }, + { + name: "calculate cost to produce 21 cars", + carsCount: 21, + want: 200000, + }, + { + name: "calculate cost to produce 37 cars", + carsCount: 37, + want: 355000, + }, + { + name: "calculate cost to produce 56 cars", + carsCount: 56, + want: 535000, + }, + { + name: "calculate cost to produce 148 cars", + carsCount: 148, + want: 1410000, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + got := CalculateCost(tc.carsCount) + if got != tc.want { + t.Errorf( + "CalculateCost(%d) = %d, want %d", + tc.carsCount, + got, + tc.want, + ) + } + }) + } +} diff --git a/go/cars-assemble/go.mod b/go/cars-assemble/go.mod new file mode 100644 index 0000000..abf0e26 --- /dev/null +++ b/go/cars-assemble/go.mod @@ -0,0 +1,3 @@ +module cars + +go 1.26 diff --git a/go/exercism.url b/go/exercism.url new file mode 100644 index 0000000..c12c82f --- /dev/null +++ b/go/exercism.url @@ -0,0 +1 @@ +https://exercism.org/tracks/go diff --git a/go/hello-world/.exercism/config.json b/go/hello-world/.exercism/config.json new file mode 100644 index 0000000..a42a358 --- /dev/null +++ b/go/hello-world/.exercism/config.json @@ -0,0 +1,35 @@ +{ + "authors": [ + "k4rtik" + ], + "contributors": [ + "bitfield", + "ekingery", + "ferhatelmas", + "hilary", + "kytrinyx", + "leenipper", + "petertseng", + "robphoenix", + "SebastianKristof", + "sebito91", + "tleen" + ], + "files": { + "solution": [ + "hello_world.go" + ], + "test": [ + "hello_world_test.go" + ], + "example": [ + ".meta/example.go" + ], + "invalidator": [ + "go.mod" + ] + }, + "blurb": "The classical introductory exercise. Just say \"Hello, World!\".", + "source": "This is an exercise to introduce users to using Exercism", + "source_url": "https://en.wikipedia.org/wiki/%22Hello,_world!%22_program" +} diff --git a/go/hello-world/.exercism/metadata.json b/go/hello-world/.exercism/metadata.json new file mode 100644 index 0000000..6b97162 --- /dev/null +++ b/go/hello-world/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"go","exercise":"hello-world","id":"a2527b7e2191407ea00beb5991895983","url":"https://exercism.org/tracks/go/exercises/hello-world","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/go/hello-world/HELP.md b/go/hello-world/HELP.md new file mode 100644 index 0000000..80bf78b --- /dev/null +++ b/go/hello-world/HELP.md @@ -0,0 +1,41 @@ +# Help + +## Running the tests + +To run the tests run the command `go test` from within the exercise directory. + +If the test suite contains benchmarks, you can run these with the `--bench` and `--benchmem` +flags: + + go test -v --bench . --benchmem + +Keep in mind that each reviewer will run benchmarks on a different machine, with +different specs, so the results from these benchmark tests may vary. + +## Submitting your solution + +You can submit your solution using the `exercism submit hello_world.go` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Go track's documentation](https://exercism.org/docs/tracks/go) +- The [Go track's programming category on the forum](https://forum.exercism.org/c/programming/go) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +To get help if you're having trouble, you can use one of the following resources: + +- [How to Write Go Code](https://golang.org/doc/code.html) +- [Effective Go](https://golang.org/doc/effective_go.html) +- [Go Resources](http://golang.org/help) +- [StackOverflow](http://stackoverflow.com/questions/tagged/go) \ No newline at end of file diff --git a/go/hello-world/README.md b/go/hello-world/README.md new file mode 100644 index 0000000..cd3adf8 --- /dev/null +++ b/go/hello-world/README.md @@ -0,0 +1,45 @@ +# Hello World + +Welcome to Hello World on Exercism's Go Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Instructions + +The classical introductory exercise. +Just say "Hello, World!". + +["Hello, World!"][hello-world] is the traditional first program for beginning programming in a new language or environment. + +The objectives are simple: + +- Modify the provided code so that it produces the string "Hello, World!". +- Run the test suite and make sure that it succeeds. +- Submit your solution and check it at the website. + +If everything goes well, you will be ready to fetch your first real exercise. + +[hello-world]: https://en.wikipedia.org/wiki/%22Hello,_world!%22_program + +## Source + +### Created by + +- @k4rtik + +### Contributed to by + +- @bitfield +- @ekingery +- @ferhatelmas +- @hilary +- @kytrinyx +- @leenipper +- @petertseng +- @robphoenix +- @SebastianKristof +- @sebito91 +- @tleen + +### Based on + +This is an exercise to introduce users to using Exercism - https://en.wikipedia.org/wiki/%22Hello,_world!%22_program \ No newline at end of file diff --git a/go/hello-world/go.mod b/go/hello-world/go.mod new file mode 100644 index 0000000..aecd42e --- /dev/null +++ b/go/hello-world/go.mod @@ -0,0 +1,3 @@ +module greeting + +go 1.18 diff --git a/go/hello-world/hello_world.go b/go/hello-world/hello_world.go new file mode 100644 index 0000000..28c166c --- /dev/null +++ b/go/hello-world/hello_world.go @@ -0,0 +1,6 @@ +package greeting + +// HelloWorld greets the world. +func HelloWorld() string { + return "Hello, World!" +} diff --git a/go/hello-world/hello_world_test.go b/go/hello-world/hello_world_test.go new file mode 100644 index 0000000..5e9c840 --- /dev/null +++ b/go/hello-world/hello_world_test.go @@ -0,0 +1,40 @@ +package greeting + +import "testing" + +// Define a function named HelloWorld that takes no arguments, +// and returns a string. +// In other words, define a function with the following signature: +// HelloWorld() string + +func TestHelloWorld(t *testing.T) { + expected := "Hello, World!" + if observed := HelloWorld(); observed != expected { + t.Fatalf("HelloWorld() = %v, want %v", observed, expected) + } +} + +// BenchmarkHelloWorld() is a benchmarking function. These functions follow the +// form `func BenchmarkXxx(*testing.B)` and can be used to test the performance +// of your implementation. They may not be present in every exercise, but when +// they are you can run them by including the `-bench` flag with the `go test` +// command, like so: `go test -v --bench . --benchmem` +// +// You will see output similar to the following: +// +// BenchmarkHelloWorld 2000000000 0.46 ns/op +// +// This means that the loop ran 2000000000 times at a speed of 0.46 ns per loop. +// +// While benchmarking can be useful to compare different iterations of the same +// exercise, keep in mind that others will run the same benchmarks on different +// machines, with different specs, so the results from these benchmark tests may +// vary. +func BenchmarkHelloWorld(b *testing.B) { + if testing.Short() { + b.Skip("skipping benchmark in short mode.") + } + for i := 0; i < b.N; i++ { + HelloWorld() + } +} diff --git a/go/lasagna/.exercism/config.json b/go/lasagna/.exercism/config.json new file mode 100644 index 0000000..089263e --- /dev/null +++ b/go/lasagna/.exercism/config.json @@ -0,0 +1,31 @@ +{ + "authors": [ + "tehsphinx" + ], + "contributors": [ + "ekingery", + "andrerfcsantos", + "bobtfish" + ], + "files": { + "solution": [ + "lasagna.go" + ], + "test": [ + "lasagna_test.go" + ], + "exemplar": [ + ".meta/exemplar.go" + ], + "invalidator": [ + "go.mod" + ] + }, + "forked_from": [ + "csharp/lucians-luscious-lasagna" + ], + "blurb": "Learn about packages, functions, and variables by helping Gopher cook lasagna.", + "custom": { + "taskIdsEnabled": true + } +} diff --git a/go/lasagna/.exercism/metadata.json b/go/lasagna/.exercism/metadata.json new file mode 100644 index 0000000..3dd6edd --- /dev/null +++ b/go/lasagna/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"go","exercise":"lasagna","id":"ff1a7a2429c741b1b4c4202a1d422002","url":"https://exercism.org/tracks/go/exercises/lasagna","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/go/lasagna/HELP.md b/go/lasagna/HELP.md new file mode 100644 index 0000000..08b9718 --- /dev/null +++ b/go/lasagna/HELP.md @@ -0,0 +1,41 @@ +# Help + +## Running the tests + +To run the tests run the command `go test` from within the exercise directory. + +If the test suite contains benchmarks, you can run these with the `--bench` and `--benchmem` +flags: + + go test -v --bench . --benchmem + +Keep in mind that each reviewer will run benchmarks on a different machine, with +different specs, so the results from these benchmark tests may vary. + +## Submitting your solution + +You can submit your solution using the `exercism submit lasagna.go` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Go track's documentation](https://exercism.org/docs/tracks/go) +- The [Go track's programming category on the forum](https://forum.exercism.org/c/programming/go) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +To get help if you're having trouble, you can use one of the following resources: + +- [How to Write Go Code](https://golang.org/doc/code.html) +- [Effective Go](https://golang.org/doc/effective_go.html) +- [Go Resources](http://golang.org/help) +- [StackOverflow](http://stackoverflow.com/questions/tagged/go) \ No newline at end of file diff --git a/go/lasagna/HINTS.md b/go/lasagna/HINTS.md new file mode 100644 index 0000000..be4c9b1 --- /dev/null +++ b/go/lasagna/HINTS.md @@ -0,0 +1,44 @@ +# Hints + +## General + +- An [integer value][integers] can be defined as one or more consecutive digits. +- If you see a `panic:` error when running the tests, this is because you have not implemented one of the functions (it should say which one) or you have left the boilerplate in place. You need to remove the `panic(...)` line from the supplied code and replace it with a real implementation. + +## 1. Define the expected oven time in minutes + +- You need to define a [constant][constants] and assign it the expected oven time in minutes. +- If you see an `undefined: OvenTime` error then double check that you have the constant defined. +- If you see an `invalid operation: got != tt.expected (mismatched types float64 and int)` error then you have likely put a decimal point into the `OvenTime` causing Go to infer the type as a floating point number. Remove the decimal and the type will be inferred as an `int`. +- If you see a `syntax error: non-declaration statement outside function body` error then it is likely that you forgot the `const` keyword. +- If you see a `syntax error: unexpected :=, expecting =` error then you are likely trying to assign the constant using `:=` like a variable; constants are assigned using `=` not `:=`. + +## 2. Calculate the remaining oven time in minutes + +- You need to define a [function][functions] with a single parameter. +- You have to [explicitly return an integer][return] from a function. +- The function's parameter is an [integer][integers]. +- You can [call][calls] one of the other functions you've defined previously. +- You can use the [mathematical operator for subtraction][operators] to subtract values. + +## 3. Calculate the preparation time in minutes + +- You need to define a [function][functions] with a single parameter. +- You have to [explicitly return an integer][return] from a function. +- The function's parameter is an [integer][integers]. +- You can use the [mathematical operator for multiplication][operators] to multiply values. + +## 4. Calculate the elapsed working time in minutes + +- You need to define a [function][functions] with two parameters. +- You have to [explicitly return an integer][return] from a function. +- The function's parameter is an [integer][integers]. +- You can [call][calls] one of the other functions you've defined previously. +- You can use the [mathematical operator for addition][operators] to add values. + +[functions]: https://tour.golang.org/basics/4 +[return]: https://golang.org/ref/spec#Return_statements +[operators]: https://golang.org/ref/spec#Operators +[integers]: https://golang.org/ref/spec#Integer_literals +[calls]: https://golang.org/ref/spec#Calls +[constants]: https://tour.golang.org/basics/15 \ No newline at end of file diff --git a/go/lasagna/README.md b/go/lasagna/README.md new file mode 100644 index 0000000..3a4b0c4 --- /dev/null +++ b/go/lasagna/README.md @@ -0,0 +1,151 @@ +# Gopher's Gorgeous Lasagna + +Welcome to Gopher's Gorgeous Lasagna on Exercism's Go Track. +If you need help running the tests or submitting your code, check out `HELP.md`. +If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :) + +## Introduction + +[Go](https://golang.org) is a statically typed, compiled programming language. +This exercise introduces three major language features: Packages, Functions, and Variables. + +## Packages + +Go applications are organized in packages. +A package is a collection of source files located in the same directory. +All source files in a directory must share the same package name. +When a package is imported, only entities (functions, types, variables, constants) whose names start with a capital letter can be used / accessed. +The recommended style of naming in Go is that identifiers will be named using `camelCase`, except for those meant to be accessible across packages which should be `PascalCase`. + +```go +package lasagna +``` + +## Variables + +Go is statically-typed, which means all variables [must have a defined type](https://en.wikipedia.org/wiki/Type_system) at compile-time. + +Variables can be defined by explicitly specifying a type: + +```go +var explicit int // Explicitly typed +``` + +You can also use an initializer, and the compiler will assign the variable type to match the type of the initializer. + +```go +implicit := 10 // Implicitly typed as an int +``` + +Once declared, variables can be assigned values using the `=` operator. +Once declared, a variable's type can never change. + +```go +count := 1 // Assign initial value +count = 2 // Update to new value + +count = false // This throws a compiler error due to assigning a non `int` type +``` + +## Constants + +Constants hold a piece of data just like variables, but their value cannot change during the execution of the program. + +Constants are defined using the `const` keyword and can be numbers, characters, strings or booleans: + +```go +const Age = 21 // Defines a numeric constant 'Age' with the value of 21 +``` + +## Functions + +Go functions accept zero or more parameters. +Parameters must be explicitly typed, there is no type inference. + +Values are returned from functions using the `return` keyword. + +A function is invoked by specifying the function name and passing arguments for each of the function's parameters. + +Note that Go supports two types of comments. +Single line comments are preceded by `//` and multiline comments are inserted between `/*` and `*/`. + +```go +package greeting + +// Hello is a public function. +func Hello (name string) string { + return hi(name) +} + +// hi is a private function. +func hi (name string) string { + return "hi " + name +} +``` + +## Instructions + +In this exercise you're going to write some code to help you cook a brilliant lasagna from your favorite cooking book. + +You have four tasks, all related to the time spent cooking the lasagna. + +## 1. Define the expected oven time in minutes + +Define the `OvenTime` constant with how many minutes the lasagna should be in the oven. According to the cooking book, the expected oven time in minutes is 40: + +```go +OvenTime +// => 40 +``` + +## 2. Calculate the remaining oven time in minutes + +Define the `RemainingOvenTime()` function that takes the actual minutes the lasagna has been in the oven as a parameter and returns how many minutes the lasagna still has to remain in the oven, based on the expected oven time in minutes from the previous task. + +```go +func RemainingOvenTime(actual int) int { + // TODO +} + +RemainingOvenTime(30) +// => 10 +``` + +## 3. Calculate the preparation time in minutes + +Define the `PreparationTime` function that takes the number of layers you added to the lasagna as a parameter and returns how many minutes you spent preparing the lasagna, assuming each layer takes you 2 minutes to prepare. + +```go +func PreparationTime(numberOfLayers int) int { + // TODO +} + +PreparationTime(2) +// => 4 +``` + +## 4. Calculate the elapsed working time in minutes + +Define the `ElapsedTime` function that takes two parameters: the first parameter is the number of layers you added to the lasagna, and the second parameter is the number of minutes the lasagna has been in the oven. +The function should return how many minutes in total you've worked on cooking the lasagna, which is the sum of the preparation time in minutes, and the time in minutes the lasagna has spent in the oven at the moment. + +```go +func ElapsedTime(numberOfLayers, actualMinutesInOven int) int { + // TODO +} + +ElapsedTime(3, 20) +// => 26 +``` + +## Source + +### Created by + +- @tehsphinx + +### Contributed to by + +- @ekingery +- @andrerfcsantos +- @bobtfish \ No newline at end of file diff --git a/go/lasagna/go.mod b/go/lasagna/go.mod new file mode 100644 index 0000000..c64fd07 --- /dev/null +++ b/go/lasagna/go.mod @@ -0,0 +1,3 @@ +module lasagna + +go 1.18 diff --git a/go/lasagna/lasagna.go b/go/lasagna/lasagna.go new file mode 100644 index 0000000..b07f115 --- /dev/null +++ b/go/lasagna/lasagna.go @@ -0,0 +1,19 @@ +package lasagna + +// TODO: define the 'OvenTime' constant +const OvenTime int = 40 + +// RemainingOvenTime returns the remaining minutes based on the `actual` minutes already in the oven. +func RemainingOvenTime(actualMinutesInOven int) int { + return OvenTime - actualMinutesInOven +} + +// PreparationTime calculates the time needed to prepare the lasagna based on the amount of layers. +func PreparationTime(numberOfLayers int) int { + return numberOfLayers * 2 +} + +// ElapsedTime calculates the time elapsed cooking the lasagna. This time includes the preparation time and the time the lasagna is baking in the oven. +func ElapsedTime(numberOfLayers, actualMinutesInOven int) int { + return PreparationTime(numberOfLayers) + actualMinutesInOven +} diff --git a/go/lasagna/lasagna_test.go b/go/lasagna/lasagna_test.go new file mode 100644 index 0000000..9ed503b --- /dev/null +++ b/go/lasagna/lasagna_test.go @@ -0,0 +1,94 @@ +package lasagna + +import "testing" + +type lasagnaTests struct { + name string + layers, time, expected int +} + +func TestOvenTime(t *testing.T) { + tests := []lasagnaTests{ + { + name: "Calculates how many minutes the lasagna should be in the oven", + layers: 0, + time: 40, + expected: 40, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := OvenTime; got != tt.expected { + t.Errorf("OvenTime(%d) = %d; want %d", tt.expected, got, tt.expected) + } + }) + } +} + +func TestRemainingOvenTime(t *testing.T) { + tests := []lasagnaTests{ + { + name: "Remaining minutes in oven", + layers: 0, + time: 15, + expected: 25, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := RemainingOvenTime(tt.time); got != tt.expected { + t.Errorf("RemainingOvenTime(%d) = %d; want %d", tt.time, got, tt.expected) + } + }) + } + +} +func TestPreparationTime(t *testing.T) { + tests := []lasagnaTests{ + { + name: "Preparation time in minutes for one layer", + layers: 1, + time: 0, + expected: 2, + }, + { + name: "Preparation time in minutes for multiple layers", + layers: 4, + time: 0, + expected: 8, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := PreparationTime(tt.layers); got != tt.expected { + t.Errorf("PreparationTime(%d) = %d; want %d", tt.layers, got, tt.expected) + } + }) + + } +} + +func TestElapsedTime(t *testing.T) { + tests := []lasagnaTests{ + { + name: "Total time in minutes for one layer", + layers: 1, + time: 30, + expected: 32, + }, + { + name: "Total time in minutes for multiple layers", + layers: 4, + time: 8, + expected: 16, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := ElapsedTime(tt.layers, tt.time); got != tt.expected { + t.Errorf("ElapsedTime(%d, %d) = %d; want %d", tt.layers, tt.time, got, tt.expected) + } + }) + + } +} diff --git a/go/raindrops/.exercism/config.json b/go/raindrops/.exercism/config.json new file mode 100644 index 0000000..5dba894 --- /dev/null +++ b/go/raindrops/.exercism/config.json @@ -0,0 +1,35 @@ +{ + "authors": [ + "nathany" + ], + "contributors": [ + "alebaffa", + "bitfield", + "ekingery", + "ferhatelmas", + "hilary", + "kytrinyx", + "leenipper", + "petertseng", + "robphoenix", + "sebito91", + "soniakeys", + "tleen", + "eklatzer" + ], + "files": { + "solution": [ + "raindrops.go" + ], + "test": [ + "raindrops_test.go", + "cases_test.go" + ], + "example": [ + ".meta/example.go" + ] + }, + "blurb": "Convert a number into its corresponding raindrop sounds - Pling, Plang and Plong.", + "source": "A variation on FizzBuzz, a famous technical interview question that is intended to weed out potential candidates. That question is itself derived from Fizz Buzz, a popular children's game for teaching division.", + "source_url": "https://en.wikipedia.org/wiki/Fizz_buzz" +} diff --git a/go/raindrops/.exercism/metadata.json b/go/raindrops/.exercism/metadata.json new file mode 100644 index 0000000..8008590 --- /dev/null +++ b/go/raindrops/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"go","exercise":"raindrops","id":"4fc80ccd49df464995e301a419919798","url":"https://exercism.org/tracks/go/exercises/raindrops","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/go/raindrops/HELP.md b/go/raindrops/HELP.md new file mode 100644 index 0000000..1c20590 --- /dev/null +++ b/go/raindrops/HELP.md @@ -0,0 +1,41 @@ +# Help + +## Running the tests + +To run the tests run the command `go test` from within the exercise directory. + +If the test suite contains benchmarks, you can run these with the `--bench` and `--benchmem` +flags: + + go test -v --bench . --benchmem + +Keep in mind that each reviewer will run benchmarks on a different machine, with +different specs, so the results from these benchmark tests may vary. + +## Submitting your solution + +You can submit your solution using the `exercism submit raindrops.go` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Go track's documentation](https://exercism.org/docs/tracks/go) +- The [Go track's programming category on the forum](https://forum.exercism.org/c/programming/go) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +To get help if you're having trouble, you can use one of the following resources: + +- [How to Write Go Code](https://golang.org/doc/code.html) +- [Effective Go](https://golang.org/doc/effective_go.html) +- [Go Resources](http://golang.org/help) +- [StackOverflow](http://stackoverflow.com/questions/tagged/go) \ No newline at end of file diff --git a/go/raindrops/README.md b/go/raindrops/README.md new file mode 100644 index 0000000..c21bf78 --- /dev/null +++ b/go/raindrops/README.md @@ -0,0 +1,59 @@ +# Raindrops + +Welcome to Raindrops on Exercism's Go Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Introduction + +Raindrops is a slightly more complex version of the FizzBuzz challenge, a classic interview question. + +## Instructions + +Your task is to convert a number into its corresponding raindrop sounds. + +If a given number: + +- is divisible by 3, add "Pling" to the result. +- is divisible by 5, add "Plang" to the result. +- is divisible by 7, add "Plong" to the result. +- **is not** divisible by 3, 5, or 7, the result should be the number as a string. + +## Examples + +- 28 is divisible by 7, but not 3 or 5, so the result would be `"Plong"`. +- 30 is divisible by 3 and 5, but not 7, so the result would be `"PlingPlang"`. +- 34 is not divisible by 3, 5, or 7, so the result would be `"34"`. + +~~~~exercism/note +A common way to test if one number is evenly divisible by another is to compare the [remainder][remainder] or [modulus][modulo] to zero. +Most languages provide operators or functions for one (or both) of these. + +[remainder]: https://exercism.org/docs/programming/operators/remainder +[modulo]: https://en.wikipedia.org/wiki/Modulo_operation +~~~~ + +## Source + +### Created by + +- @nathany + +### Contributed to by + +- @alebaffa +- @bitfield +- @ekingery +- @ferhatelmas +- @hilary +- @kytrinyx +- @leenipper +- @petertseng +- @robphoenix +- @sebito91 +- @soniakeys +- @tleen +- @eklatzer + +### Based on + +A variation on FizzBuzz, a famous technical interview question that is intended to weed out potential candidates. That question is itself derived from Fizz Buzz, a popular children's game for teaching division. - https://en.wikipedia.org/wiki/Fizz_buzz \ No newline at end of file diff --git a/go/raindrops/cases_test.go b/go/raindrops/cases_test.go new file mode 100644 index 0000000..75bf5cf --- /dev/null +++ b/go/raindrops/cases_test.go @@ -0,0 +1,105 @@ +package raindrops + +// This is an auto-generated file. Do not change it manually. Run the generator to update the file. +// See https://github.com/exercism/go#synchronizing-tests-and-instructions +// Source: exercism/problem-specifications +// Commit: 25c2ae5 build(deps): bump fast-uri from 3.1.0 to 3.1.2 (#2653) + +type testCase struct { + description string + input int + expected string +} + +var testCases = []testCase{ + { + description: "the sound for 1 is 1", + input: 1, + expected: "1", + }, + { + description: "the sound for 3 is Pling", + input: 3, + expected: "Pling", + }, + { + description: "the sound for 5 is Plang", + input: 5, + expected: "Plang", + }, + { + description: "the sound for 7 is Plong", + input: 7, + expected: "Plong", + }, + { + description: "the sound for 6 is Pling as it has a factor 3", + input: 6, + expected: "Pling", + }, + { + description: "2 to the power 3 does not make a raindrop sound as 3 is the exponent not the base", + input: 8, + expected: "8", + }, + { + description: "the sound for 9 is Pling as it has a factor 3", + input: 9, + expected: "Pling", + }, + { + description: "the sound for 10 is Plang as it has a factor 5", + input: 10, + expected: "Plang", + }, + { + description: "the sound for 14 is Plong as it has a factor of 7", + input: 14, + expected: "Plong", + }, + { + description: "the sound for 15 is PlingPlang as it has factors 3 and 5", + input: 15, + expected: "PlingPlang", + }, + { + description: "the sound for 21 is PlingPlong as it has factors 3 and 7", + input: 21, + expected: "PlingPlong", + }, + { + description: "the sound for 25 is Plang as it has a factor 5", + input: 25, + expected: "Plang", + }, + { + description: "the sound for 27 is Pling as it has a factor 3", + input: 27, + expected: "Pling", + }, + { + description: "the sound for 35 is PlangPlong as it has factors 5 and 7", + input: 35, + expected: "PlangPlong", + }, + { + description: "the sound for 49 is Plong as it has a factor 7", + input: 49, + expected: "Plong", + }, + { + description: "the sound for 52 is 52", + input: 52, + expected: "52", + }, + { + description: "the sound for 105 is PlingPlangPlong as it has factors 3, 5 and 7", + input: 105, + expected: "PlingPlangPlong", + }, + { + description: "the sound for 3125 is Plang as it has a factor 5", + input: 3125, + expected: "Plang", + }, +} diff --git a/go/raindrops/go.mod b/go/raindrops/go.mod new file mode 100644 index 0000000..f92f8f3 --- /dev/null +++ b/go/raindrops/go.mod @@ -0,0 +1,3 @@ +module raindrops + +go 1.26 diff --git a/go/raindrops/raindrops.go b/go/raindrops/raindrops.go new file mode 100644 index 0000000..6b3ab98 --- /dev/null +++ b/go/raindrops/raindrops.go @@ -0,0 +1,8 @@ +package raindrops + +func Convert(number int) string { + var NumberAsString = "" + var OutputString = "" + if () + panic("Please implement the Convert function") +} diff --git a/go/raindrops/raindrops_test.go b/go/raindrops/raindrops_test.go new file mode 100644 index 0000000..fdda5bb --- /dev/null +++ b/go/raindrops/raindrops_test.go @@ -0,0 +1,21 @@ +package raindrops + +import "testing" + +func TestConvert(t *testing.T) { + for _, tc := range testCases { + t.Run(tc.description, func(t *testing.T) { + if actual := Convert(tc.input); actual != tc.expected { + t.Fatalf("Convert(%d) = %q, want: %q", tc.input, actual, tc.expected) + } + }) + } +} + +func BenchmarkConvert(b *testing.B) { + for b.Loop() { + for _, test := range testCases { + Convert(test.input) + } + } +} diff --git a/go/weather-forecast/.exercism/config.json b/go/weather-forecast/.exercism/config.json new file mode 100644 index 0000000..4331163 --- /dev/null +++ b/go/weather-forecast/.exercism/config.json @@ -0,0 +1,24 @@ +{ + "authors": [ + "nikimanoledaki", + "micuffaro" + ], + "files": { + "solution": [ + "weather_forecast.go" + ], + "test": [ + "weather_forecast_test.go" + ], + "exemplar": [ + ".meta/exemplar.go" + ], + "invalidator": [ + "go.mod" + ] + }, + "blurb": "Learn about comments by helping a weather station manage their weather forecasting program.", + "custom": { + "taskIdsEnabled": false + } +} diff --git a/go/weather-forecast/.exercism/metadata.json b/go/weather-forecast/.exercism/metadata.json new file mode 100644 index 0000000..af14474 --- /dev/null +++ b/go/weather-forecast/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"go","exercise":"weather-forecast","id":"a9e0603772514be1b32ccb5505fce949","url":"https://exercism.org/tracks/go/exercises/weather-forecast","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/go/weather-forecast/HELP.md b/go/weather-forecast/HELP.md new file mode 100644 index 0000000..6047b12 --- /dev/null +++ b/go/weather-forecast/HELP.md @@ -0,0 +1,41 @@ +# Help + +## Running the tests + +To run the tests run the command `go test` from within the exercise directory. + +If the test suite contains benchmarks, you can run these with the `--bench` and `--benchmem` +flags: + + go test -v --bench . --benchmem + +Keep in mind that each reviewer will run benchmarks on a different machine, with +different specs, so the results from these benchmark tests may vary. + +## Submitting your solution + +You can submit your solution using the `exercism submit weather_forecast.go` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Go track's documentation](https://exercism.org/docs/tracks/go) +- The [Go track's programming category on the forum](https://forum.exercism.org/c/programming/go) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +To get help if you're having trouble, you can use one of the following resources: + +- [How to Write Go Code](https://golang.org/doc/code.html) +- [Effective Go](https://golang.org/doc/effective_go.html) +- [Go Resources](http://golang.org/help) +- [StackOverflow](http://stackoverflow.com/questions/tagged/go) \ No newline at end of file diff --git a/go/weather-forecast/HINTS.md b/go/weather-forecast/HINTS.md new file mode 100644 index 0000000..484da62 --- /dev/null +++ b/go/weather-forecast/HINTS.md @@ -0,0 +1,20 @@ +# Hints + +## General + +- A [documentation comment][comment] should be written directly before the entity that it is describing, start with the name of what it is describing, take the form of a sentence, and end with a period. + +## 1. Document package weather + +- The [package comment][comment] should be written directly before the package, start with `Package x`, and end with a period. + +## 2. Document the CurrentCondition and CurrentLocation variables + +- The [variable comment][variable comment] should be written right before the variable that it is describing, start with its name, and end with a period. + +## 3. Document the Forecast() function + +- The [function comment][comment] should come directly before the function, start with the name of the function and end with a period. + +[comment]: https://golang.org/doc/effective_go.html#commentary +[variable comment]: https://dave.cheney.net/practical-go/presentations/qcon-china.html#_comments \ No newline at end of file diff --git a/go/weather-forecast/README.md b/go/weather-forecast/README.md new file mode 100644 index 0000000..338d3dd --- /dev/null +++ b/go/weather-forecast/README.md @@ -0,0 +1,66 @@ +# Weather Forecast + +Welcome to Weather Forecast on Exercism's Go Track. +If you need help running the tests or submitting your code, check out `HELP.md`. +If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :) + +## Introduction + +In the previous exercise, we saw that there are two ways to write comments in Go: single-line comments that are preceded by `//`, and multiline comment blocks that are wrapped with `/*` and `*/`. + +## Documentation comments + +In Go, comments play an important role in documenting code. They are used by the `godoc` command, which extracts these comments to create documentation about Go packages. A documentation comment should be a complete sentence that starts with the name of the thing being described and ends with a period. + +Comments should precede packages as well as exported identifiers, for example exported functions, methods, package variables, constants, and structs, which you will learn more about in the next exercises. + +A package-level variable can look like this: + +```go +// TemperatureCelsius represents a certain temperature in degrees Celsius. +var TemperatureCelsius float64 +``` + +## Package comments + +Package comments should be written directly before a package clause (`package x`) and begin with `Package x ...` like this: + +```go +// Package kelvin provides tools to convert +// temperatures to and from Kelvin. +package kelvin +``` + +## Function comments + +A function comment should be written directly before the function declaration. It should be a full sentence that starts with the function name. For example, an exported comment for the function `Calculate` should take the form `Calculate ...`. It should also explain what arguments the function takes, what it does with them, and what its return values mean, ending in a period): + +```go +// CelsiusFreezingTemp returns an integer value equal to the temperature at which water freezes in degrees Celsius. +func CelsiusFreezingTemp() int { + return 0 +} +``` + +## Instructions + +Goblinocus is a country that takes its weather forecast very seriously. Since you are a renowned, responsible and proficient developer, they asked you to write a program that can forecast the current weather condition of various cities in Goblinocus. You were busy at the time and asked one of your friends to do the job instead. After a while, the president of Goblinocus contacted you and said they do not understand your friend's code. When you check the code, you discover that your friend did not act as a responsible programmer and there are no comments in the code. You feel obligated to clarify the program so goblins can understand them as well. + +## 1. Document package weather + +Since goblins are not as smart as you are, they forgot what the package should do for them. Please write a comment for `package weather` that describes its contents. The package comment should introduce the package and provide information relevant to the package as a whole. + +## 2. Document the CurrentCondition and CurrentLocation variables + +The president of Goblinocus is a bit paranoid and fears uncommented variables are used to destroy their country. Please clarify the usage of the package variables `CurrentCondition` and `CurrentLocation` and put the president's mind at ease. This should tell any user of the package what information the variables store, and what they can do with it. + +## 3. Document the Forecast() function + +Goblinocus forecast operators want to know what the `Forecast()` function does (but do not tell them how it works, since unfortunately, they will get more confused). Please write a comment for this function that describes what the function does, but not how it does it. + +## Source + +### Created by + +- @nikimanoledaki +- @micuffaro \ No newline at end of file diff --git a/go/weather-forecast/go.mod b/go/weather-forecast/go.mod new file mode 100644 index 0000000..cbea8d2 --- /dev/null +++ b/go/weather-forecast/go.mod @@ -0,0 +1,3 @@ +module weather + +go 1.18 \ No newline at end of file diff --git a/go/weather-forecast/weather_forecast.go b/go/weather-forecast/weather_forecast.go new file mode 100644 index 0000000..0999fb3 --- /dev/null +++ b/go/weather-forecast/weather_forecast.go @@ -0,0 +1,13 @@ +// Package weather provides tools to help in weather forecast. +package weather + +// CurrentCondition represents the current weather condition. +var CurrentCondition string +// CurrentLocation represents the current location to get weather information. +var CurrentLocation string + +// Forecast returns information about the weather in the given location. +func Forecast(city, condition string) string { + CurrentLocation, CurrentCondition = city, condition + return CurrentLocation + " - current weather condition: " + CurrentCondition +} diff --git a/go/weather-forecast/weather_forecast_test.go b/go/weather-forecast/weather_forecast_test.go new file mode 100644 index 0000000..d8596b8 --- /dev/null +++ b/go/weather-forecast/weather_forecast_test.go @@ -0,0 +1,140 @@ +package weather + +import ( + "fmt" + "go/ast" + "go/parser" + "go/token" + "strings" + "testing" +) + +func TestComments(t *testing.T) { + filename := "weather_forecast.go" + + fs := token.NewFileSet() + f, err := parser.ParseFile(fs, filename, nil, parser.ParseComments) + if err != nil { + t.Fatal(err) + } + + wantedComments := 4 + got := len(f.Comments) + if got != wantedComments { + t.Errorf("Incorrect number of comments: got %d, want %d", got, wantedComments) + } + + testPackageComment(t, f) + + ast.Inspect(f, func(node ast.Node) bool { + switch n := node.(type) { + case *ast.GenDecl: + if n.Lparen.IsValid() { + for _, v := range n.Specs { + testBlockIdentifierComment(t, v.(*ast.ValueSpec)) + } + } else { + testIdentifierComment(t, n) + } + case *ast.FuncDecl: + testFunctionComment(t, n) + } + return true + }) +} + +func testPackageComment(t *testing.T, node *ast.File) { + t.Helper() + if node.Doc == nil { + t.Errorf("Package weather should have a comment") + } + + packageName := node.Name.Name + want := "Package " + packageName + packageComment := node.Doc.Text() + + if ok, errStr := testComment("Package", packageName, packageComment, want); !ok { + t.Error(errStr) + } + +} +func testIdentifierComment(t *testing.T, node *ast.GenDecl) { + t.Helper() + + identifierName := node.Specs[0].(*ast.ValueSpec).Names[0].Name + if node.Doc == nil { + t.Errorf("Exported identifier %s should have a comment", identifierName) + } + + identifierComment := node.Doc.Text() + want := identifierName + + if ok, errStr := testComment("Variable", identifierName, identifierComment, want); !ok { + t.Error(errStr) + } +} + +func testBlockIdentifierComment(t *testing.T, node *ast.ValueSpec) { + t.Helper() + + identifierName := node.Names[0].Name + if node.Doc == nil { + t.Errorf("Exported identifier %s should have a comment", identifierName) + } + + identifierComment := node.Doc.Text() + want := identifierName + + if ok, errStr := testComment("Variable", identifierName, identifierComment, want); !ok { + t.Error(errStr) + } + +} + +func testFunctionComment(t *testing.T, node *ast.FuncDecl) { + t.Helper() + funcName := node.Name.Name + if node.Doc == nil { + t.Errorf("Exported function %s() should have a comment", funcName) + } + + funcComment := node.Doc.Text() + want := funcName + + if ok, errStr := testComment("Function", funcName, funcComment, want); !ok { + t.Error(errStr) + } +} + +func testComment(entityKind, entityName, comment, wantedPrefix string) (ok bool, errString string) { + + trimmedComment := strings.TrimSpace(comment) + lowerEntity := strings.ToLower(entityKind) + + // Check if comment has wanted prefix + if !strings.HasPrefix(trimmedComment, wantedPrefix) { + errorString := fmt.Sprintf("%s comment for %s '%s' should start with '// %s ...': got '// %s'", + entityKind, lowerEntity, entityName, wantedPrefix, trimmedComment) + return false, errorString + } + + // Check if comment content is empty + commentContent := strings.TrimPrefix(trimmedComment, wantedPrefix) + commentContent = strings.TrimSpace(commentContent) + commentContent = strings.TrimSuffix(commentContent, ".") + + if commentContent == "" { + lowerEntity := strings.ToLower(entityKind) + errorString := fmt.Sprintf("%s comment of '%s' should provide a description of the %s, e.g '// %s <%s_description>'", + entityKind, entityName, lowerEntity, wantedPrefix, lowerEntity) + return false, errorString + } + + // Check if comment ends in a period + if !strings.HasSuffix(trimmedComment, ".") { + return false, fmt.Sprintf("%s comment for %s '%s' should end with a period (.)", + entityKind, lowerEntity, entityName) + } + + return true, "" +} diff --git a/python/anagram/.exercism/config.json b/python/anagram/.exercism/config.json new file mode 100644 index 0000000..6dee5e1 --- /dev/null +++ b/python/anagram/.exercism/config.json @@ -0,0 +1,38 @@ +{ + "authors": [], + "contributors": [ + "behrtam", + "cmccandless", + "crazymykl", + "Dog", + "dotrungkien", + "henrik", + "ikhadykin", + "kytrinyx", + "lowks", + "markijbema", + "N-Parsons", + "n1k0", + "pheanex", + "roadfoodr", + "sjakobi", + "thomasjpfan", + "tqa236", + "vgerak", + "yawpitch" + ], + "files": { + "solution": [ + "anagram.py" + ], + "test": [ + "anagram_test.py" + ], + "example": [ + ".meta/example.py" + ] + }, + "blurb": "Given a word and a list of possible anagrams, select the correct sublist.", + "source": "Inspired by the Extreme Startup game", + "source_url": "https://github.com/rchatley/extreme_startup" +} diff --git a/python/anagram/.exercism/metadata.json b/python/anagram/.exercism/metadata.json new file mode 100644 index 0000000..efe5ffe --- /dev/null +++ b/python/anagram/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"anagram","id":"7031d739171c414490bfc8ee0955d6e0","url":"https://exercism.org/tracks/python/exercises/anagram","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/anagram/HELP.md b/python/anagram/HELP.md new file mode 100644 index 0000000..66a6cfc --- /dev/null +++ b/python/anagram/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +
+ +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit anagram.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/anagram/README.md b/python/anagram/README.md new file mode 100644 index 0000000..77e3933 --- /dev/null +++ b/python/anagram/README.md @@ -0,0 +1,58 @@ +# Anagram + +Welcome to Anagram on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Introduction + +At a garage sale, you find a lovely vintage typewriter at a bargain price! +Excitedly, you rush home, insert a sheet of paper, and start typing away. +However, your excitement wanes when you examine the output: all words are garbled! +For example, it prints "stop" instead of "post" and "least" instead of "stale." +Carefully, you try again, but now it prints "spot" and "slate." +After some experimentation, you find there is a random delay before each letter is printed, which messes up the order. +You now understand why they sold it for so little money! + +You realize this quirk allows you to generate anagrams, which are words formed by rearranging the letters of another word. +Pleased with your finding, you spend the rest of the day generating hundreds of anagrams. + +## Instructions + +Given a target word and one or more candidate words, your task is to find the candidates that are anagrams of the target. + +An anagram is a rearrangement of letters to form a new word: for example `"owns"` is an anagram of `"snow"`. +A word is _not_ its own anagram: for example, `"stop"` is not an anagram of `"stop"`. + +The target word and candidate words are made up of one or more ASCII alphabetic characters (`A`-`Z` and `a`-`z`). +Lowercase and uppercase characters are equivalent: for example, `"PoTS"` is an anagram of `"sTOp"`, but `"StoP"` is not an anagram of `"sTOp"`. +The words you need to find should be taken from the candidate words, using the same letter case. + +Given the target `"stone"` and the candidate words `"stone"`, `"tones"`, `"banana"`, `"tons"`, `"notes"`, and `"Seton"`, the anagram words you need to find are `"tones"`, `"notes"`, and `"Seton"`. + +## Source + +### Contributed to by + +- @behrtam +- @cmccandless +- @crazymykl +- @Dog +- @dotrungkien +- @henrik +- @ikhadykin +- @kytrinyx +- @lowks +- @markijbema +- @N-Parsons +- @n1k0 +- @pheanex +- @roadfoodr +- @sjakobi +- @thomasjpfan +- @tqa236 +- @vgerak +- @yawpitch + +### Based on + +Inspired by the Extreme Startup game - https://github.com/rchatley/extreme_startup \ No newline at end of file diff --git a/python/anagram/__pycache__/anagram.cpython-313.pyc b/python/anagram/__pycache__/anagram.cpython-313.pyc new file mode 100644 index 0000000..0863341 Binary files /dev/null and b/python/anagram/__pycache__/anagram.cpython-313.pyc differ diff --git a/python/anagram/__pycache__/anagram.cpython-314.pyc b/python/anagram/__pycache__/anagram.cpython-314.pyc new file mode 100644 index 0000000..c96843a Binary files /dev/null and b/python/anagram/__pycache__/anagram.cpython-314.pyc differ diff --git a/python/anagram/__pycache__/anagram_test.cpython-313-pytest-8.3.4.pyc b/python/anagram/__pycache__/anagram_test.cpython-313-pytest-8.3.4.pyc new file mode 100644 index 0000000..c35f288 Binary files /dev/null and b/python/anagram/__pycache__/anagram_test.cpython-313-pytest-8.3.4.pyc differ diff --git a/python/anagram/__pycache__/anagram_test.cpython-314-pytest-9.1.0.pyc b/python/anagram/__pycache__/anagram_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..c3c76b0 Binary files /dev/null and b/python/anagram/__pycache__/anagram_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/anagram/anagram.py b/python/anagram/anagram.py new file mode 100644 index 0000000..fc763f3 --- /dev/null +++ b/python/anagram/anagram.py @@ -0,0 +1,12 @@ +def find_anagrams(word, candidates): + anagrams_list: list[str] = [] + for candidate in candidates: + if word.lower() != candidate.lower() and len(word) == len(candidate): + is_anagram_flag: bool = True + for letter in word.lower(): + if word.lower().count(letter) != candidate.lower().count(letter): + is_anagram_flag = False + break + if is_anagram_flag: + anagrams_list.append(candidate) + return anagrams_list diff --git a/python/anagram/anagram_test.py b/python/anagram/anagram_test.py new file mode 100644 index 0000000..48b99ec --- /dev/null +++ b/python/anagram/anagram_test.py @@ -0,0 +1,105 @@ +# These tests are auto-generated with test data from: +# https://github.com/exercism/problem-specifications/tree/main/exercises/anagram/canonical-data.json +# File last updated on 2024-02-28 + +import unittest + +from anagram import ( + find_anagrams, +) + + +class AnagramTest(unittest.TestCase): + def test_no_matches(self): + candidates = ["hello", "world", "zombies", "pants"] + expected = [] + self.assertCountEqual(find_anagrams("diaper", candidates), expected) + + def test_detects_two_anagrams(self): + candidates = ["lemons", "cherry", "melons"] + expected = ["lemons", "melons"] + self.assertCountEqual(find_anagrams("solemn", candidates), expected) + + def test_does_not_detect_anagram_subsets(self): + candidates = ["dog", "goody"] + expected = [] + self.assertCountEqual(find_anagrams("good", candidates), expected) + + def test_detects_anagram(self): + candidates = ["enlists", "google", "inlets", "banana"] + expected = ["inlets"] + self.assertCountEqual(find_anagrams("listen", candidates), expected) + + def test_detects_three_anagrams(self): + candidates = ["gallery", "ballerina", "regally", "clergy", "largely", "leading"] + expected = ["gallery", "regally", "largely"] + self.assertCountEqual(find_anagrams("allergy", candidates), expected) + + def test_detects_multiple_anagrams_with_different_case(self): + candidates = ["Eons", "ONES"] + expected = ["Eons", "ONES"] + self.assertCountEqual(find_anagrams("nose", candidates), expected) + + def test_does_not_detect_non_anagrams_with_identical_checksum(self): + candidates = ["last"] + expected = [] + self.assertCountEqual(find_anagrams("mass", candidates), expected) + + def test_detects_anagrams_case_insensitively(self): + candidates = ["cashregister", "Carthorse", "radishes"] + expected = ["Carthorse"] + self.assertCountEqual(find_anagrams("Orchestra", candidates), expected) + + def test_detects_anagrams_using_case_insensitive_subject(self): + candidates = ["cashregister", "carthorse", "radishes"] + expected = ["carthorse"] + self.assertCountEqual(find_anagrams("Orchestra", candidates), expected) + + def test_detects_anagrams_using_case_insensitive_possible_matches(self): + candidates = ["cashregister", "Carthorse", "radishes"] + expected = ["Carthorse"] + self.assertCountEqual(find_anagrams("orchestra", candidates), expected) + + def test_does_not_detect_an_anagram_if_the_original_word_is_repeated(self): + candidates = ["goGoGO"] + expected = [] + self.assertCountEqual(find_anagrams("go", candidates), expected) + + def test_anagrams_must_use_all_letters_exactly_once(self): + candidates = ["patter"] + expected = [] + self.assertCountEqual(find_anagrams("tapper", candidates), expected) + + def test_words_are_not_anagrams_of_themselves(self): + candidates = ["BANANA"] + expected = [] + self.assertCountEqual(find_anagrams("BANANA", candidates), expected) + + def test_words_are_not_anagrams_of_themselves_even_if_letter_case_is_partially_different( + self, + ): + candidates = ["Banana"] + expected = [] + self.assertCountEqual(find_anagrams("BANANA", candidates), expected) + + def test_words_are_not_anagrams_of_themselves_even_if_letter_case_is_completely_different( + self, + ): + candidates = ["banana"] + expected = [] + self.assertCountEqual(find_anagrams("BANANA", candidates), expected) + + def test_words_other_than_themselves_can_be_anagrams(self): + candidates = ["LISTEN", "Silent"] + expected = ["Silent"] + self.assertCountEqual(find_anagrams("LISTEN", candidates), expected) + + def test_handles_case_of_greek_letters(self): + candidates = ["ΒΓΑ", "ΒΓΔ", "γβα", "αβγ"] + expected = ["ΒΓΑ", "γβα"] + self.assertCountEqual(find_anagrams("ΑΒΓ", candidates), expected) + + def test_different_characters_may_have_the_same_bytes(self): + candidates = ["€a"] + expected = [] + self.assertCountEqual(find_anagrams("a⬂", candidates), expected) diff --git a/python/armstrong-numbers/.exercism/config.json b/python/armstrong-numbers/.exercism/config.json new file mode 100644 index 0000000..2febbd2 --- /dev/null +++ b/python/armstrong-numbers/.exercism/config.json @@ -0,0 +1,27 @@ +{ + "authors": [ + "pheanex" + ], + "contributors": [ + "BethanyG", + "cmccandless", + "Dog", + "K4cePhoenix", + "sukovanej", + "tqa236" + ], + "files": { + "solution": [ + "armstrong_numbers.py" + ], + "test": [ + "armstrong_numbers_test.py" + ], + "example": [ + ".meta/example.py" + ] + }, + "blurb": "Determine if a number is an Armstrong number.", + "source": "Wikipedia", + "source_url": "https://en.wikipedia.org/wiki/Narcissistic_number" +} diff --git a/python/armstrong-numbers/.exercism/metadata.json b/python/armstrong-numbers/.exercism/metadata.json new file mode 100644 index 0000000..1d6be65 --- /dev/null +++ b/python/armstrong-numbers/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"armstrong-numbers","id":"638a18575d6e4c5cb072d8f6d5dfe702","url":"https://exercism.org/tracks/python/exercises/armstrong-numbers","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/armstrong-numbers/HELP.md b/python/armstrong-numbers/HELP.md new file mode 100644 index 0000000..a28a778 --- /dev/null +++ b/python/armstrong-numbers/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +
+ +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit armstrong_numbers.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/armstrong-numbers/README.md b/python/armstrong-numbers/README.md new file mode 100644 index 0000000..fe5f76b --- /dev/null +++ b/python/armstrong-numbers/README.md @@ -0,0 +1,38 @@ +# Armstrong Numbers + +Welcome to Armstrong Numbers on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Instructions + +An [Armstrong number][armstrong-number] is a number that is the sum of its own digits each raised to the power of the number of digits. + +For example: + +- 9 is an Armstrong number, because `9 = 9^1 = 9` +- 10 is _not_ an Armstrong number, because `10 != 1^2 + 0^2 = 1` +- 153 is an Armstrong number, because: `153 = 1^3 + 5^3 + 3^3 = 1 + 125 + 27 = 153` +- 154 is _not_ an Armstrong number, because: `154 != 1^3 + 5^3 + 4^3 = 1 + 125 + 64 = 190` + +Write some code to determine whether a number is an Armstrong number. + +[armstrong-number]: https://en.wikipedia.org/wiki/Narcissistic_number + +## Source + +### Created by + +- @pheanex + +### Contributed to by + +- @BethanyG +- @cmccandless +- @Dog +- @K4cePhoenix +- @sukovanej +- @tqa236 + +### Based on + +Wikipedia - https://en.wikipedia.org/wiki/Narcissistic_number \ No newline at end of file diff --git a/python/armstrong-numbers/__pycache__/armstrong_numbers.cpython-313.pyc b/python/armstrong-numbers/__pycache__/armstrong_numbers.cpython-313.pyc new file mode 100644 index 0000000..d16fd81 Binary files /dev/null and b/python/armstrong-numbers/__pycache__/armstrong_numbers.cpython-313.pyc differ diff --git a/python/armstrong-numbers/__pycache__/armstrong_numbers.cpython-314.pyc b/python/armstrong-numbers/__pycache__/armstrong_numbers.cpython-314.pyc new file mode 100644 index 0000000..86bfafe Binary files /dev/null and b/python/armstrong-numbers/__pycache__/armstrong_numbers.cpython-314.pyc differ diff --git a/python/armstrong-numbers/__pycache__/armstrong_numbers_test.cpython-313-pytest-8.3.4.pyc b/python/armstrong-numbers/__pycache__/armstrong_numbers_test.cpython-313-pytest-8.3.4.pyc new file mode 100644 index 0000000..42f254e Binary files /dev/null and b/python/armstrong-numbers/__pycache__/armstrong_numbers_test.cpython-313-pytest-8.3.4.pyc differ diff --git a/python/armstrong-numbers/__pycache__/armstrong_numbers_test.cpython-314-pytest-9.1.0.pyc b/python/armstrong-numbers/__pycache__/armstrong_numbers_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..5d25ac2 Binary files /dev/null and b/python/armstrong-numbers/__pycache__/armstrong_numbers_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/armstrong-numbers/armstrong_numbers.py b/python/armstrong-numbers/armstrong_numbers.py new file mode 100644 index 0000000..36b7325 --- /dev/null +++ b/python/armstrong-numbers/armstrong_numbers.py @@ -0,0 +1,7 @@ +def is_armstrong_number(number): + literal: str = str(number) + nr_digits: int = len(literal) + sum_of_digits: int = 0 + for pos in range(nr_digits): + sum_of_digits += int(literal[pos]) ** nr_digits + return sum_of_digits == number diff --git a/python/armstrong-numbers/armstrong_numbers_test.py b/python/armstrong-numbers/armstrong_numbers_test.py new file mode 100644 index 0000000..4024766 --- /dev/null +++ b/python/armstrong-numbers/armstrong_numbers_test.py @@ -0,0 +1,38 @@ +# These tests are auto-generated with test data from: +# https://github.com/exercism/problem-specifications/tree/main/exercises/armstrong-numbers/canonical-data.json +# File last updated on 2023-07-20 + +import unittest + +from armstrong_numbers import ( + is_armstrong_number, +) + + +class ArmstrongNumbersTest(unittest.TestCase): + def test_zero_is_an_armstrong_number(self): + self.assertIs(is_armstrong_number(0), True) + + def test_single_digit_numbers_are_armstrong_numbers(self): + self.assertIs(is_armstrong_number(5), True) + + def test_there_are_no_two_digit_armstrong_numbers(self): + self.assertIs(is_armstrong_number(10), False) + + def test_three_digit_number_that_is_an_armstrong_number(self): + self.assertIs(is_armstrong_number(153), True) + + def test_three_digit_number_that_is_not_an_armstrong_number(self): + self.assertIs(is_armstrong_number(100), False) + + def test_four_digit_number_that_is_an_armstrong_number(self): + self.assertIs(is_armstrong_number(9474), True) + + def test_four_digit_number_that_is_not_an_armstrong_number(self): + self.assertIs(is_armstrong_number(9475), False) + + def test_seven_digit_number_that_is_an_armstrong_number(self): + self.assertIs(is_armstrong_number(9926315), True) + + def test_seven_digit_number_that_is_not_an_armstrong_number(self): + self.assertIs(is_armstrong_number(9926314), False) diff --git a/python/atbash-cipher/.exercism/config.json b/python/atbash-cipher/.exercism/config.json new file mode 100644 index 0000000..5df5062 --- /dev/null +++ b/python/atbash-cipher/.exercism/config.json @@ -0,0 +1,33 @@ +{ + "authors": [ + "betegelse" + ], + "contributors": [ + "behrtam", + "cmccandless", + "Dog", + "ikhadykin", + "jgomo3", + "kytrinyx", + "N-Parsons", + "parinporecha", + "pheanex", + "sjakobi", + "thomasjpfan", + "tqa236" + ], + "files": { + "solution": [ + "atbash_cipher.py" + ], + "test": [ + "atbash_cipher_test.py" + ], + "example": [ + ".meta/example.py" + ] + }, + "blurb": "Create an implementation of the Atbash cipher, an ancient encryption system created in the Middle East.", + "source": "Wikipedia", + "source_url": "https://en.wikipedia.org/wiki/Atbash" +} diff --git a/python/atbash-cipher/.exercism/metadata.json b/python/atbash-cipher/.exercism/metadata.json new file mode 100644 index 0000000..bb91003 --- /dev/null +++ b/python/atbash-cipher/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"atbash-cipher","id":"93a4d551fe7d4b36be4720e467aaa8a9","url":"https://exercism.org/tracks/python/exercises/atbash-cipher","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/atbash-cipher/HELP.md b/python/atbash-cipher/HELP.md new file mode 100644 index 0000000..90e344d --- /dev/null +++ b/python/atbash-cipher/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +
+ +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit atbash_cipher.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/atbash-cipher/README.md b/python/atbash-cipher/README.md new file mode 100644 index 0000000..cc5d254 --- /dev/null +++ b/python/atbash-cipher/README.md @@ -0,0 +1,57 @@ +# Atbash Cipher + +Welcome to Atbash Cipher on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Instructions + +Create an implementation of the Atbash cipher, an ancient encryption system created in the Middle East. + +The Atbash cipher is a simple substitution cipher that relies on transposing all the letters in the alphabet such that the resulting alphabet is backwards. +The first letter is replaced with the last letter, the second with the second-last, and so on. + +An Atbash cipher for the Latin alphabet would be as follows: + +```text +Plain: abcdefghijklmnopqrstuvwxyz +Cipher: zyxwvutsrqponmlkjihgfedcba +``` + +It is a very weak cipher because it only has one possible key, and it is a simple mono-alphabetic substitution cipher. +However, this may not have been an issue in the cipher's time. + +Ciphertext is written out in groups of fixed length, the traditional group size being 5 letters, leaving numbers unchanged, and punctuation is excluded. +This is to make it harder to guess things based on word boundaries. +All text will be encoded as lowercase letters. + +## Examples + +- Encoding `test` gives `gvhg` +- Encoding `x123 yes` gives `c123b vh` +- Decoding `gvhg` gives `test` +- Decoding `gsvjf rxpyi ldmul cqfnk hlevi gsvoz abwlt` gives `thequickbrownfoxjumpsoverthelazydog` + +## Source + +### Created by + +- @betegelse + +### Contributed to by + +- @behrtam +- @cmccandless +- @Dog +- @ikhadykin +- @jgomo3 +- @kytrinyx +- @N-Parsons +- @parinporecha +- @pheanex +- @sjakobi +- @thomasjpfan +- @tqa236 + +### Based on + +Wikipedia - https://en.wikipedia.org/wiki/Atbash \ No newline at end of file diff --git a/python/atbash-cipher/__pycache__/atbash_cipher.cpython-313.pyc b/python/atbash-cipher/__pycache__/atbash_cipher.cpython-313.pyc new file mode 100644 index 0000000..d88c1f8 Binary files /dev/null and b/python/atbash-cipher/__pycache__/atbash_cipher.cpython-313.pyc differ diff --git a/python/atbash-cipher/__pycache__/atbash_cipher.cpython-314.pyc b/python/atbash-cipher/__pycache__/atbash_cipher.cpython-314.pyc new file mode 100644 index 0000000..53db8cf Binary files /dev/null and b/python/atbash-cipher/__pycache__/atbash_cipher.cpython-314.pyc differ diff --git a/python/atbash-cipher/__pycache__/atbash_cipher_test.cpython-313-pytest-8.3.5.pyc b/python/atbash-cipher/__pycache__/atbash_cipher_test.cpython-313-pytest-8.3.5.pyc new file mode 100644 index 0000000..7dda642 Binary files /dev/null and b/python/atbash-cipher/__pycache__/atbash_cipher_test.cpython-313-pytest-8.3.5.pyc differ diff --git a/python/atbash-cipher/__pycache__/atbash_cipher_test.cpython-314-pytest-9.1.0.pyc b/python/atbash-cipher/__pycache__/atbash_cipher_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..a7391a5 Binary files /dev/null and b/python/atbash-cipher/__pycache__/atbash_cipher_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/atbash-cipher/atbash_cipher.py b/python/atbash-cipher/atbash_cipher.py new file mode 100644 index 0000000..ec275c7 --- /dev/null +++ b/python/atbash-cipher/atbash_cipher.py @@ -0,0 +1,30 @@ +def encode(plain_text: str) -> str: + encoded_text: str = "" + weight: int = 0 + for char in plain_text.lower(): + if char.isalpha(): + encoded_text += chr(97 + 25 - (ord(char) - 97)) + weight += 1 + elif char.isdigit(): + encoded_text += char + weight += 1 + else: + continue + if (weight % 5) == 0: + encoded_text += " " + # remove space at the end when it exists + if encoded_text[-1] == " ": + return encoded_text[0:-1] + return encoded_text + + +def decode(ciphered_text: str) -> str: + decoded_text: str = "" + for char in ciphered_text.lower(): + if char.isalpha(): + decoded_text += chr(122 - 25 + (122 - ord(char))) + elif char.isdigit(): + decoded_text += char + else: + continue + return decoded_text diff --git a/python/atbash-cipher/atbash_cipher_test.py b/python/atbash-cipher/atbash_cipher_test.py new file mode 100644 index 0000000..f8103f8 --- /dev/null +++ b/python/atbash-cipher/atbash_cipher_test.py @@ -0,0 +1,65 @@ +# These tests are auto-generated with test data from: +# https://github.com/exercism/problem-specifications/tree/main/exercises/atbash-cipher/canonical-data.json +# File last updated on 2023-07-20 + +import unittest + +from atbash_cipher import ( + decode, + encode, +) + + +class AtbashCipherTest(unittest.TestCase): + def test_encode_yes(self): + self.assertEqual(encode("yes"), "bvh") + + def test_encode_no(self): + self.assertEqual(encode("no"), "ml") + + def test_encode_omg(self): + self.assertEqual(encode("OMG"), "lnt") + + def test_encode_spaces(self): + self.assertEqual(encode("O M G"), "lnt") + + def test_encode_mindblowingly(self): + self.assertEqual(encode("mindblowingly"), "nrmwy oldrm tob") + + def test_encode_numbers(self): + self.assertEqual(encode("Testing,1 2 3, testing."), "gvhgr mt123 gvhgr mt") + + def test_encode_deep_thought(self): + self.assertEqual(encode("Truth is fiction."), "gifgs rhurx grlm") + + def test_encode_all_the_letters(self): + self.assertEqual( + encode("The quick brown fox jumps over the lazy dog."), + "gsvjf rxpyi ldmul cqfnk hlevi gsvoz abwlt", + ) + + def test_decode_exercism(self): + self.assertEqual(decode("vcvix rhn"), "exercism") + + def test_decode_a_sentence(self): + self.assertEqual( + decode("zmlyh gzxov rhlug vmzhg vkkrm thglm v"), + "anobstacleisoftenasteppingstone", + ) + + def test_decode_numbers(self): + self.assertEqual(decode("gvhgr mt123 gvhgr mt"), "testing123testing") + + def test_decode_all_the_letters(self): + self.assertEqual( + decode("gsvjf rxpyi ldmul cqfnk hlevi gsvoz abwlt"), + "thequickbrownfoxjumpsoverthelazydog", + ) + + def test_decode_with_too_many_spaces(self): + self.assertEqual(decode("vc vix r hn"), "exercism") + + def test_decode_with_no_spaces(self): + self.assertEqual( + decode("zmlyhgzxovrhlugvmzhgvkkrmthglmv"), "anobstacleisoftenasteppingstone" + ) diff --git a/python/binary-search/.exercism/config.json b/python/binary-search/.exercism/config.json new file mode 100644 index 0000000..8b76b59 --- /dev/null +++ b/python/binary-search/.exercism/config.json @@ -0,0 +1,35 @@ +{ + "authors": [ + "michaelkunc" + ], + "contributors": [ + "AnAccountForReportingBugs", + "behrtam", + "BethanyG", + "cmccandless", + "Dog", + "fortrieb", + "ikhadykin", + "kytrinyx", + "mpatibandla", + "N-Parsons", + "patricksjackson", + "pheanex", + "subkrish", + "tqa236" + ], + "files": { + "solution": [ + "binary_search.py" + ], + "test": [ + "binary_search_test.py" + ], + "example": [ + ".meta/example.py" + ] + }, + "blurb": "Implement a binary search algorithm.", + "source": "Wikipedia", + "source_url": "https://en.wikipedia.org/wiki/Binary_search_algorithm" +} diff --git a/python/binary-search/.exercism/metadata.json b/python/binary-search/.exercism/metadata.json new file mode 100644 index 0000000..4a1699a --- /dev/null +++ b/python/binary-search/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"binary-search","id":"b5256f28c8a741168d520136d8106a26","url":"https://exercism.org/tracks/python/exercises/binary-search","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/binary-search/HELP.md b/python/binary-search/HELP.md new file mode 100644 index 0000000..70b82b5 --- /dev/null +++ b/python/binary-search/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +
+ +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit binary_search.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/binary-search/README.md b/python/binary-search/README.md new file mode 100644 index 0000000..7f5a9f6 --- /dev/null +++ b/python/binary-search/README.md @@ -0,0 +1,88 @@ +# Binary Search + +Welcome to Binary Search on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Introduction + +You have stumbled upon a group of mathematicians who are also singer-songwriters. +They have written a song for each of their favorite numbers, and, as you can imagine, they have a lot of favorite numbers (like [0][zero] or [73][seventy-three] or [6174][kaprekars-constant]). + +You are curious to hear the song for your favorite number, but with so many songs to wade through, finding the right song could take a while. +Fortunately, they have organized their songs in a playlist sorted by the title — which is simply the number that the song is about. + +You realize that you can use a binary search algorithm to quickly find a song given the title. + +[zero]: https://en.wikipedia.org/wiki/0 +[seventy-three]: https://en.wikipedia.org/wiki/73_(number) +[kaprekars-constant]: https://en.wikipedia.org/wiki/6174_(number) + +## Instructions + +Your task is to implement a binary search algorithm. + +A binary search algorithm finds an item in a list by repeatedly splitting it in half, only keeping the half which contains the item we're looking for. +It allows us to quickly narrow down the possible locations of our item until we find it, or until we've eliminated all possible locations. + +~~~~exercism/caution +Binary search only works when a list has been sorted. +~~~~ + +The algorithm looks like this: + +- Find the middle element of a _sorted_ list and compare it with the item we're looking for. +- If the middle element is our item, then we're done! +- If the middle element is greater than our item, we can eliminate that element and all the elements **after** it. +- If the middle element is less than our item, we can eliminate that element and all the elements **before** it. +- If every element of the list has been eliminated then the item is not in the list. +- Otherwise, repeat the process on the part of the list that has not been eliminated. + +Here's an example: + +Let's say we're looking for the number 23 in the following sorted list: `[4, 8, 12, 16, 23, 28, 32]`. + +- We start by comparing 23 with the middle element, 16. +- Since 23 is greater than 16, we can eliminate the left half of the list, leaving us with `[23, 28, 32]`. +- We then compare 23 with the new middle element, 28. +- Since 23 is less than 28, we can eliminate the right half of the list: `[23]`. +- We've found our item. + +## Exception messages + +Sometimes it is necessary to [raise an exception](https://docs.python.org/3/tutorial/errors.html#raising-exceptions). When you do this, you should always include a **meaningful error message** to indicate what the source of the error is. This makes your code more readable and helps significantly with debugging. For situations where you know that the error source will be a certain type, you can choose to raise one of the [built in error types](https://docs.python.org/3/library/exceptions.html#base-classes), but should still include a meaningful message. + +This particular exercise requires that you use the [raise statement](https://docs.python.org/3/reference/simple_stmts.html#the-raise-statement) to "throw" a `ValueError` when the given value is not found within the array. The tests will only pass if you both `raise` the `exception` and include a message with it. + +To raise a `ValueError` with a message, write the message as an argument to the `exception` type: + +```python +# example when value is not found in the array. +raise ValueError("value not in array") +``` + +## Source + +### Created by + +- @michaelkunc + +### Contributed to by + +- @AnAccountForReportingBugs +- @behrtam +- @BethanyG +- @cmccandless +- @Dog +- @fortrieb +- @ikhadykin +- @kytrinyx +- @mpatibandla +- @N-Parsons +- @patricksjackson +- @pheanex +- @subkrish +- @tqa236 + +### Based on + +Wikipedia - https://en.wikipedia.org/wiki/Binary_search_algorithm \ No newline at end of file diff --git a/python/binary-search/__pycache__/binary_search.cpython-313.pyc b/python/binary-search/__pycache__/binary_search.cpython-313.pyc new file mode 100644 index 0000000..9aedcfd Binary files /dev/null and b/python/binary-search/__pycache__/binary_search.cpython-313.pyc differ diff --git a/python/binary-search/__pycache__/binary_search.cpython-314.pyc b/python/binary-search/__pycache__/binary_search.cpython-314.pyc new file mode 100644 index 0000000..23d31fa Binary files /dev/null and b/python/binary-search/__pycache__/binary_search.cpython-314.pyc differ diff --git a/python/binary-search/__pycache__/binary_search_test.cpython-313-pytest-8.3.4.pyc b/python/binary-search/__pycache__/binary_search_test.cpython-313-pytest-8.3.4.pyc new file mode 100644 index 0000000..4099749 Binary files /dev/null and b/python/binary-search/__pycache__/binary_search_test.cpython-313-pytest-8.3.4.pyc differ diff --git a/python/binary-search/__pycache__/binary_search_test.cpython-313-pytest-8.3.5.pyc b/python/binary-search/__pycache__/binary_search_test.cpython-313-pytest-8.3.5.pyc new file mode 100644 index 0000000..2b7a662 Binary files /dev/null and b/python/binary-search/__pycache__/binary_search_test.cpython-313-pytest-8.3.5.pyc differ diff --git a/python/binary-search/__pycache__/binary_search_test.cpython-314-pytest-9.1.0.pyc b/python/binary-search/__pycache__/binary_search_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..af1874c Binary files /dev/null and b/python/binary-search/__pycache__/binary_search_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/binary-search/binary_search.py b/python/binary-search/binary_search.py new file mode 100644 index 0000000..83cb75c --- /dev/null +++ b/python/binary-search/binary_search.py @@ -0,0 +1,28 @@ +# iterative version of the code +# def find(search_list: list[int], value: int) -> int: +# left: int = 0 +# right: int = len(search_list) - 1 +# search_list.sort() +# while left <= right: +# middle_index: int = (left + right) // 2 +# if value < search_list[middle_index]: +# right = middle_index - 1 +# elif value > search_list[middle_index]: +# left = middle_index + 1 +# else: +# return middle_index +# raise ValueError(f"value not in array") + + +# recursive version of the code +def find(search_list: list[int], value: int) -> int: + middle_index: int = (len(search_list) - 1) // 2 + search_list.sort() + if search_list == []: + raise ValueError("value not in array") + if value < search_list[middle_index]: + return find(search_list[:middle_index], value) + elif value > search_list[middle_index]: + return (middle_index + 1) + find(search_list[middle_index + 1:], value) + else: + return middle_index diff --git a/python/binary-search/binary_search_test.py b/python/binary-search/binary_search_test.py new file mode 100644 index 0000000..2ee50d4 --- /dev/null +++ b/python/binary-search/binary_search_test.py @@ -0,0 +1,67 @@ +# These tests are auto-generated with test data from: +# https://github.com/exercism/problem-specifications/tree/main/exercises/binary-search/canonical-data.json +# File last updated on 2023-07-20 + +import unittest + +from binary_search import ( + find, +) + + +class BinarySearchTest(unittest.TestCase): + def test_finds_a_value_in_an_array_with_one_element(self): + self.assertEqual(find([6], 6), 0) + + def test_finds_a_value_in_the_middle_of_an_array(self): + self.assertEqual(find([1, 3, 4, 6, 8, 9, 11], 6), 3) + + def test_finds_a_value_at_the_beginning_of_an_array(self): + self.assertEqual(find([1, 3, 4, 6, 8, 9, 11], 1), 0) + + def test_finds_a_value_at_the_end_of_an_array(self): + self.assertEqual(find([1, 3, 4, 6, 8, 9, 11], 11), 6) + + def test_finds_a_value_in_an_array_of_odd_length(self): + self.assertEqual( + find([1, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 634], 144), 9 + ) + + def test_finds_a_value_in_an_array_of_even_length(self): + self.assertEqual( + find([1, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377], 21), 5) + + def test_identifies_that_a_value_is_not_included_in_the_array(self): + with self.assertRaises(ValueError) as err: + find([1, 3, 4, 6, 8, 9, 11], 7) + + self.assertEqual(type(err.exception), ValueError) + self.assertEqual(err.exception.args[0], "value not in array") + + def test_a_value_smaller_than_the_array_s_smallest_value_is_not_found(self): + with self.assertRaises(ValueError) as err: + find([1, 3, 4, 6, 8, 9, 11], 0) + + self.assertEqual(type(err.exception), ValueError) + self.assertEqual(err.exception.args[0], "value not in array") + + def test_a_value_larger_than_the_array_s_largest_value_is_not_found(self): + with self.assertRaises(ValueError) as err: + find([1, 3, 4, 6, 8, 9, 11], 13) + + self.assertEqual(type(err.exception), ValueError) + self.assertEqual(err.exception.args[0], "value not in array") + + def test_nothing_is_found_in_an_empty_array(self): + with self.assertRaises(ValueError) as err: + find([], 1) + + self.assertEqual(type(err.exception), ValueError) + self.assertEqual(err.exception.args[0], "value not in array") + + def test_nothing_is_found_when_the_left_and_right_bounds_cross(self): + with self.assertRaises(ValueError) as err: + find([1, 2], 0) + + self.assertEqual(type(err.exception), ValueError) + self.assertEqual(err.exception.args[0], "value not in array") diff --git a/python/binary-search/rascunhos.rnote b/python/binary-search/rascunhos.rnote new file mode 100644 index 0000000..da5a5dd Binary files /dev/null and b/python/binary-search/rascunhos.rnote differ diff --git a/python/black-jack/.exercism/config.json b/python/black-jack/.exercism/config.json new file mode 100644 index 0000000..a23fa9e --- /dev/null +++ b/python/black-jack/.exercism/config.json @@ -0,0 +1,27 @@ +{ + "authors": [ + "Ticktakto", + "Yabby1997", + "limm-jk", + "OMEGA-Y", + "wnstj2007", + "pranasziaukas", + "bethanyG" + ], + "contributors": [ + "PaulT89" + ], + "files": { + "solution": [ + "black_jack.py" + ], + "test": [ + "black_jack_test.py" + ], + "exemplar": [ + ".meta/exemplar.py" + ] + }, + "icon": "poker", + "blurb": "Learn about comparisons by implementing some Black Jack judging rules." +} diff --git a/python/black-jack/.exercism/metadata.json b/python/black-jack/.exercism/metadata.json new file mode 100644 index 0000000..efedb76 --- /dev/null +++ b/python/black-jack/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"black-jack","id":"9e1cc775a71046d1a495346a5c712920","url":"https://exercism.org/tracks/python/exercises/black-jack","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/black-jack/HELP.md b/python/black-jack/HELP.md new file mode 100644 index 0000000..970b1fa --- /dev/null +++ b/python/black-jack/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +
+ +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit black_jack.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/black-jack/HINTS.md b/python/black-jack/HINTS.md new file mode 100644 index 0000000..aaa0273 --- /dev/null +++ b/python/black-jack/HINTS.md @@ -0,0 +1,45 @@ +# Hints + +[The Python comparisons tutorial][python comparisons tutorial] and [Python comparisons examples][python comparisons examples] are a great introduction covering the content of this exercise. + +## 1. Calculate the value of a card + +- You can use the equality comparison operator `==` to determine if a card is an ace card: `card == 'A'`. +- You can use the containment operator `in` to determine if a substring is contained inside a string: `'Q' in 'KJQ'`. +- You can use the [`int` constructor][int constructor] to convert a `str` of an `int` to an `int`: `int('13')`. + +## 2. Determine which card has a higher value + +- Once you have defined the `value_of_card` function, you can call it from other functions. +- You can use the value comparison operators `>` and `<` to determine if specific cards are _greater than_ or _less than_ a given value: `3 < 12`. +- You can use the equality comparison operator `==` to determine if two values are equal to one another. + +## 3. Calculate the value of an ace + +- Once you have defined the `value_of_card` function, you can call it from other functions. +- You can use the order comparison operator `>` to decide the appropriate course of action here. + +## 4. Determine Blackjack + +- Remember, you can use the [`if`/`elif`/`else` syntax][if syntax] to handle different combinations of cards. +- You can chain BOTH comparison operators and boolean operators _arbitrarily_: `y < z < x` or `(y or z) and (x or z)` +- You can reuse the already implemented `value_of_card` function. + +## 5. Splitting pairs + +- You can reuse the already implemented `value_of_card` function. +- You can handle the `A` case (when at least one of the cards in an ace) separately. + +## 6. Doubling down + +- An `A` scored at 11 will never allow doubling down if there are two cards in the hand. +- Given the first point, you _should_ be able to reuse the already implemented `value_of_card` function. +- You can chain comparison operators _arbitrarily_: `y < z < x`. +- You can use the [conditional expression][conditional expression] (_sometimes called a "ternary operator"_) + to shorten simple `if`/`else` statements: `13 if letter == 'M' else 3`. + +[conditional expression]: https://docs.python.org/3/reference/expressions.html#conditional-expressions +[if syntax]: https://docs.python.org/3/tutorial/controlflow.html#if-statements +[int constructor]: https://docs.python.org/3/library/functions.html#int +[python comparisons examples]: https://www.tutorialspoint.com/python/comparison_operators_example.htm +[python comparisons tutorial]: https://docs.python.org/3/reference/expressions.html#comparisons \ No newline at end of file diff --git a/python/black-jack/README.md b/python/black-jack/README.md new file mode 100644 index 0000000..bd8d281 --- /dev/null +++ b/python/black-jack/README.md @@ -0,0 +1,395 @@ +# Black Jack + +Welcome to Black Jack on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. +If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :) + +## Introduction + +## Comparisons + +Python supports the following basic comparison operators: + +| Operator | Operation | Description | +| -------- | -------------------------- | ------------------------------------------------------------------------- | +| `>` | "greater than" | `a > b` is `True` if `a` is **strictly** greater in value than `b` | +| `<` | "less than" | `a < b` is `True` if `a` is **strictly** less in value than `b` | +| `==` | "equal to" | `a == b` is `True` if `a` is **strictly** equal to `b` in value | +| `>=` | "greater than or equal to" | `a >= b` is `True` if `a > b` OR `a == b` in value | +| `<=` | "less than or equal to" | `a <= b` is `True` if `a < b` or `a == b` in value | +| `!=` | "not equal to" | `a != b` is `True` if `a == b` is `False` | +| `is` | "identity" | `a is b` is `True` if **_and only if_** `a` and `b` are the same _object_ | +| `is not` | "negated identity" | `a is not b` is `True` if `a` and `b` are **not** the same _object_ | +| `in` | "containment test" | `a in b` is `True` if `a` is member, subset, or element of `b` | +| `not in` | "negated containment test" | `a not in b` is `True` if `a` is not a member, subset, or element of `b` | + +They all have the same priority (_which is higher than that of [Boolean operations][boolean operations], but lower than that of arithmetic or bitwise operations_). + +## Comparison between different data types + +Objects that are different types (_except numeric types_) never compare equal by default. +Non-identical instances of a `class` will also _**not**_ compare as equal unless the `class` defines special [rich comparison][rich comparisons] methods that customize the default `object` comparison behavior. +Customizing via `rich comparisons` will be covered in a follow-on exercise. +For (much) more detail on this topic, see [Value comparisons][value comparisons] in the Python documentation. + +Numeric types are (mostly) an exception to this type matching rule. +An `integer` **can** be considered equal to a `float` (_or an [`octal`][octal] equal to a [`hexadecimal`][hex]_), as long as the types can be implicitly converted for comparison. + +For the other numeric types in the Python standard library ([complex][complex numbers], [decimal][decimal numbers], [fractions][rational numbers]), comparison operators are defined where they "make sense" (_where implicit conversion does not change the outcome_), but throw a `TypeError` if the underlying objects cannot be accurately converted for comparison. +For more information on the rules that python uses for _numeric conversion_, see [arithmetic conversions][arithmetic conversions] in the Python documentation. + +```python +>>> import fractions + +# A string cannot be converted to an int. +>>> 17 == '17' +False + +# An int can be converted to float for comparison. +>>> 17 == 17.0 +True + +# The fraction 6/3 can be converted to the int 2 +# The int 2 can be converted to 0b10 in binary. +>>> 6/3 == 0b10 +True + +# An int can be converted to a complex number with a 0 imaginary part. +>>> 17 == complex(17) +True + +# The fraction 2/5 can be converted to the float 0.4 +>>> 0.4 == 2/5 +True + +>>> complex(2/5, 1/2) == complex(0.4, 0.5) +True +``` + +Any ordered comparison of a number to a `NaN` (_not a number_) type is `False`. +A confusing side effect of Python's `NaN` definition is that `NaN` never compares equal to `NaN`. + +```python +>>> x = float('NaN') + +>>> 3 < x +False + +>>> x < 3 +False + +# NaN never compares equal to NaN +>>> x == x +False +``` + +## Comparing Strings + +Unlike numbers, strings (`str`) are compared [_lexicographically_][lexographic order], using their individual Unicode code points (_the result of passing each code point in the `str` to the built-in function [`ord()`][ord], which returns an `int`_). +If all code points in both strings match and are _**in the same order**_, the two strings are considered equal. +This comparison is done in a 'pair-wise' fashion - first-to-first, second-to-second, etc. +In Python 3.x, `str` and `bytes` cannot be directly coerced/compared. + +```python +>>> 'Python' > 'Rust' +False + +>>> 'Python' > 'JavaScript' +True + +# Examples with Mandarin. +# hello < goodbye +>>> '你好' < '再见' +True + +# ord() of first characters +>>> ord('你'), ord('再') +(20320, 20877) + +# ord() of second characters +>>> ord('好'), ord('见') +(22909, 35265) + +# And with Korean words. +# Pretty < beautiful. +>>> '예쁜' < '아름다운' +False + +>>> ord('예'), ord('아') +(50696, 50500) +``` + +## Comparison Chaining + +Comparison operators can be chained _arbitrarily_ -- meaning that they can be used in any combination of any length. +Note that the evaluation of an expression takes place from `left` to `right`. + +As an example, `x < y <= z` is equivalent to `x < y` `and` `y <= z`, except that `y` is evaluated **only once**. +In both cases, `z` is _not_ evaluated **at all** when `x < y` is found to be `False`. +This is often called `short-circuit evaluation` - the evaluation stops if the truth value of the expression has already been determined. + +`Short circuiting` is supported by various boolean operators, functions, and also by comparison chaining in Python. +Unlike many other programming languages, including `C`, `C++`, `C#`, and `Java`, chained expressions like `a < b < c` in Python have a conventional [mathematical interpretation][three way boolean comparison] and precedence. + +```python +>>> x = 2 +>>> y = 5 +>>> z = 10 + +>>> x < y < z +True + +>>> x < y > z +False + +>>> x > y < z +False +``` + +## Comparing object identity + +The operators `is` and `is not` test for object [_identity_][object identity], as opposed to object _value_. +An object's identity never changes after creation and can be found by using the [`id()`][id function] function. + +` is ` evaluates to `True` if _**and only if**_ `id()` == `id()`. +` is not ` yields the inverse. + +Due to their singleton status, `None` and `NotImplemented` should always be compared to items using `is` and `is not`. +See the Python reference docs on [value comparisons][value comparisons none] and [PEP8][pep8 programming recommendations] for more details on this convention. + +```python +>>> my_fav_numbers = [1, 2, 3] + +>>> your_fav_numbers = my_fav_numbers + +>>> my_fav_numbers is your_fav_numbers +True + +# The returned id will differ by system and python version. +>>> id(my_fav_numbers) +4517478208 + +# your_fav_numbers is only an alias pointing to the original my_fav_numbers object. +# Assigning a new name does not create a new object. +>>> id(your_fav_numbers) +4517478208 + + +>>> my_fav_numbers is not your_fav_numbers +False + +>>> my_fav_numbers is not None +True + +>>> my_fav_numbers is NotImplemented +False +``` + +## Membership comparisons + +The operators `in` and `not in` test for _membership_. +` in ` evaluates to `True` if `` is a member of `` (_if `` is a subset of or is contained within ``_), and evaluates `False` otherwise. +` not in ` returns the negation, or _opposite of_ ` in `. + +For string and bytes types, ` in ` is `True` _**if and only if**_ `` is a substring of ``. + +```python +# A set of lucky numbers. +>>> lucky_numbers = {11, 22, 33} +>>> 22 in lucky_numbers +True + +>>> 44 in lucky_numbers +False + +# A dictionary of employee information. +>>> employee = {'name': 'John Doe', + 'id': 67826, 'age': 33, + 'title': 'ceo'} + +# Checking for the membership of certain keys. +>>> 'age' in employee +True + +>>> 33 in employee +False + +>>> 'lastname' not in employee +True + +# Checking for substring membership +>>> name = 'Super Batman' +>>> 'Bat' in name +True + +>>> 'Batwoman' in name +False +``` + +[arithmetic conversions]: https://docs.python.org/3/reference/expressions.html?highlight=number%20conversion#arithmetic-conversions +[boolean operations]: https://docs.python.org/3/library/stdtypes.html#boolean-operations-and-or-not +[complex numbers]: https://docs.python.org/3/library/functions.html#complex +[decimal numbers]: https://docs.python.org/3/library/decimal.html +[hex]: https://docs.python.org/3/library/functions.html?highlight=hex#hex +[id function]: https://docs.python.org/3/library/functions.html#id +[lexographic order]: https://en.wikipedia.org/wiki/Lexicographic_order +[object identity]: https://docs.python.org/3/reference/datamodel.html +[octal]: https://docs.python.org/3/library/functions.html?#oct +[ord]: https://docs.python.org/3/library/functions.html#ord +[pep8 programming recommendations]: https://pep8.org/#programming-recommendations +[rational numbers]: https://docs.python.org/3/library/fractions.html +[rich comparisons]: https://docs.python.org/3/reference/datamodel.html#object.__lt__ +[three way boolean comparison]: https://en.wikipedia.org/wiki/Three-way_comparison +[value comparisons none]: https://docs.python.org/3/reference/expressions.html?highlight=none#value-comparisons +[value comparisons]: https://docs.python.org/3/reference/expressions.html?highlight=nan#value-comparisons + +## Instructions + +In this exercise you are going to implement some rules of [Blackjack][blackjack], +such as the way the game is played and scored. + +**Note** : In this exercise, _`A`_ means ace, _`J`_ means jack, _`Q`_ means queen, and _`K`_ means king. +Jokers are discarded. +A [standard French-suited 52-card deck][standard_deck] is assumed, but in most versions, several decks are shuffled together for play. + +## 1. Calculate the value of a card + +In Blackjack, it is up to each individual player if an ace is worth 1 or 11 points (_more on that later_). +Face cards (`J`, `Q`, `K`) are scored at 10 points and any other card is worth its "pip" (_numerical_) value. + +Define the `value_of_card()` function with parameter `card`. +The function should return the _numerical value_ of the passed-in card string. +Since an ace can take on multiple values (1 **or** 11), this function should fix the value of an ace card at 1 for the time being. +Later on, you will implement a function to determine the value of an ace card, given an existing hand. + +```python +>>> value_of_card('K') +10 + +>>> value_of_card('4') +4 + +>>> value_of_card('A') +1 +``` + +## 2. Determine which card has a higher value + +Define the `higher_card(, )` function having parameters `card_one` and `card_two`. +For scoring purposes, the value of `J`, `Q` or `K` is 10. +The function should return which card has the higher value for scoring. +If both cards have an equal value, return both. +Returning both cards can be done by using a comma in the `return` statement: + +```python +# Using a comma in a return creates a Tuple. Tuples will be covered in a later exercise. +>>> def returning_two_values(value_one, value_two): + return value_one, value_two + +>>> returning_two_values('K', '3') +('K', '3') +``` + +An ace can take on multiple values, so we will fix `A` cards to a value of 1 for this task. + +```python +>>> higher_card('K', '10') +('K', '10') + +>>> higher_card('4', '6') +'6' + +>>> higher_card('K', 'A') +'K' +``` + +## 3. Calculate the value of an ace + +As mentioned before, an ace can be worth _either_ 1 **or** 11 points. +Players try to get as close as possible to a score of 21, without going _over_ 21 (_going "bust"_). + +Define the `value_of_ace(, )` function with parameters `card_one` and `card_two`, which are a pair of cards already in the hand _before_ getting an ace card. +Your function will have to decide if the upcoming ace will get a value of 1 or a value of 11, and return that value. +Remember: the value of the hand with the ace needs to be as high as possible _without_ going over 21. + +**Hint**: if we already have an ace in hand, then the value for the upcoming ace would be 1. + +```python +>>> value_of_ace('6', 'K') +1 + +>>> value_of_ace('7', '3') +11 +``` + +## 4. Determine a "Natural" or "Blackjack" Hand + +If a player is dealt an ace (`A`) and a ten-card (10, `K`, `Q`, or `J`) as their first two cards, then the player has a score of 21. +This is known as a **blackjack** hand. + + +Define the `is_blackjack(, )` function with parameters `card_one` and `card_two`, which are a pair of cards. +Determine if the two-card hand is a **blackjack**, and return the boolean `True` if it is, `False` otherwise. + +**Note** : The score _calculation_ can be done in many ways. +But if possible, we'd like you to check if there is an ace and a ten-card **_in_** the hand (_or at a certain position_), as opposed to _summing_ the hand values. + +```python +>>> is_blackjack('A', 'K') +True + +>>> is_blackjack('10', '9') +False +``` + +## 5. Splitting pairs + +If the players first two cards are of the same value, such as two sixes, or a `Q` and `K` a player may choose to treat them as two separate hands. +This is known as "splitting pairs". + +Define the `can_split_pairs(, )` function with parameters `card_one` and `card_two`, which are a pair of cards. +Determine if this two-card hand can be split into two pairs. +If the hand can be split, return the boolean `True` otherwise, return `False` + +```python +>>> can_split_pairs('Q', 'K') +True + +>>> can_split_pairs('10', 'A') +False +``` + +## 6. Doubling down + +When the original two cards dealt total 9, 10, or 11 points, a player can place an additional bet equal to their original bet. +This is known as "doubling down". + +Define the `can_double_down(, )` function with parameters `card_one` and `card_two`, which are a pair of cards. +Determine if the two-card hand can be "doubled down", and return the boolean `True` if it can, `False` otherwise. + +```python +>>> can_double_down('A', '9') +True + +>>> can_double_down('10', '2') +False +``` + +[blackjack]: https://bicyclecards.com/how-to-play/blackjack/ +[standard_deck]: https://en.wikipedia.org/wiki/Standard_52-card_deck + +## Source + +### Created by + +- @Ticktakto +- @Yabby1997 +- @limm-jk +- @OMEGA-Y +- @wnstj2007 +- @pranasziaukas +- @bethanyG + +### Contributed to by + +- @PaulT89 \ No newline at end of file diff --git a/python/black-jack/__pycache__/black_jack.cpython-313.pyc b/python/black-jack/__pycache__/black_jack.cpython-313.pyc new file mode 100644 index 0000000..3938fd2 Binary files /dev/null and b/python/black-jack/__pycache__/black_jack.cpython-313.pyc differ diff --git a/python/black-jack/__pycache__/black_jack.cpython-314.pyc b/python/black-jack/__pycache__/black_jack.cpython-314.pyc new file mode 100644 index 0000000..4a9d0d0 Binary files /dev/null and b/python/black-jack/__pycache__/black_jack.cpython-314.pyc differ diff --git a/python/black-jack/__pycache__/black_jack_test.cpython-313-pytest-8.3.4.pyc b/python/black-jack/__pycache__/black_jack_test.cpython-313-pytest-8.3.4.pyc new file mode 100644 index 0000000..7014375 Binary files /dev/null and b/python/black-jack/__pycache__/black_jack_test.cpython-313-pytest-8.3.4.pyc differ diff --git a/python/black-jack/__pycache__/black_jack_test.cpython-314-pytest-9.1.0.pyc b/python/black-jack/__pycache__/black_jack_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..a085411 Binary files /dev/null and b/python/black-jack/__pycache__/black_jack_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/black-jack/black_jack.py b/python/black-jack/black_jack.py new file mode 100644 index 0000000..7857b96 --- /dev/null +++ b/python/black-jack/black_jack.py @@ -0,0 +1,103 @@ +"""Functions to help play and score a game of blackjack. + +How to play blackjack: https://bicyclecards.com/how-to-play/blackjack/ +"Standard" playing cards: https://en.wikipedia.org/wiki/Standard_52-card_deck +""" + + +def value_of_card(card): + """Determine the scoring value of a card. + + :param card: str - given card. + :return: int - value of a given card. See below for values. + + 1. 'J', 'Q', or 'K' (otherwise known as "face cards") = 10 + 2. 'A' (ace card) = 1 + 3. '2' - '10' = numerical value. + """ + match card: + case "J" | "Q" | "K": + return 10 + case "A": + return 1 + case _: + return int(card) + + +def higher_card(card_one, card_two): + """Determine which card has a higher value in the hand. + + :param card_one, card_two: str - cards dealt in hand. See below for values. + :return: str or tuple - resulting Tuple contains both cards if they are of equal value. + + 1. 'J', 'Q', or 'K' (otherwise known as "face cards") = 10 + 2. 'A' (ace card) = 1 + 3. '2' - '10' = numerical value. + """ + if value_of_card(card_one) > value_of_card(card_two): + return card_one + if value_of_card(card_one) < value_of_card(card_two): + return card_two + return (card_one, card_two) + + +def value_of_ace(card_one, card_two): + """Calculate the most advantageous value for the ace card. + + :param card_one, card_two: str - card dealt. See below for values. + :return: int - either 1 or 11 value of the upcoming ace card. + + 1. 'J', 'Q', or 'K' (otherwise known as "face cards") = 10 + 2. 'A' (ace card) = 11 (if already in hand) + 3. '2' - '10' = numerical value. + """ + card_one_value: int = 11 if card_one == "A" else value_of_card(card_one) + card_two_value: int = 11 if card_two == "A" else value_of_card(card_two) + if card_one_value + card_two_value <= 10: + return 11 + return 1 + + +def is_blackjack(card_one, card_two): + """Determine if the hand is a 'natural' or 'blackjack'. + + :param card_one, card_two: str - card dealt. See below for values. + :return: bool - is the hand is a blackjack (two cards worth 21). + + 1. 'J', 'Q', or 'K' (otherwise known as "face cards") = 10 + 2. 'A' (ace card) = 11 (if already in hand) + 3. '2' - '10' = numerical value. + """ + card_one_value: int = 11 if card_one == "A" else value_of_card(card_one) + card_two_value: int = 0 + if card_one == "A": + card_two_value = value_of_card(card_two) + else: + card_two_value = 11 if card_two == "A" else value_of_card(card_two) + if card_one_value + card_two_value == 21: + return True + return False + + +def can_split_pairs(card_one, card_two): + """Determine if a player can split their hand into two hands. + + :param card_one, card_two: str - cards dealt. + :return: bool - can the hand be split into two pairs? (i.e. cards are of the same value). + """ + if value_of_card(card_one) == value_of_card(card_two): + return True + return False + + +def can_double_down(card_one, card_two): + """Determine if a blackjack player can place a double down bet. + + :param card_one, card_two: str - first and second cards in hand. + :return: bool - can the hand can be doubled down? (i.e. totals 9, 10 or 11 points). + """ + match value_of_card(card_one) + value_of_card(card_two): + case 9 | 10 | 11: + return True + case _: + return False diff --git a/python/black-jack/black_jack_test.py b/python/black-jack/black_jack_test.py new file mode 100644 index 0000000..0962781 --- /dev/null +++ b/python/black-jack/black_jack_test.py @@ -0,0 +1,114 @@ +import unittest +import pytest + +from black_jack import ( + value_of_card, + higher_card, + value_of_ace, + is_blackjack, + can_split_pairs, + can_double_down + ) + + +class BlackJackTest(unittest.TestCase): + + @pytest.mark.task(taskno=1) + def test_value_of_card(self): + test_data = [('2', 2), ('5', 5), ('8', 8), + ('A', 1), ('10', 10), ('J', 10), + ('Q', 10), ('K', 10)] + + for variant, (card, expected) in enumerate(test_data, 1): + with self.subTest(f'variation #{variant}', card=card, expected=expected): + actual_result = value_of_card(card) + error_msg = (f'Called value_of_card({card}). ' + f'The function returned {actual_result} as the value of the {card} card, ' + f'but the test expected {expected} as the {card} card value.') + + self.assertEqual(actual_result, expected, msg=error_msg) + + + @pytest.mark.task(taskno=2) + def test_higher_card(self): + test_data = [('A', 'A', ('A', 'A')), + ('10', 'J', ('10', 'J')), + ('3', 'A', '3'), + ('3', '6', '6'), + ('Q', '10', ('Q', '10')), + ('4', '4', ('4', '4')), + ('9', '10', '10'), + ('6', '9', '9'), + ('4', '8', '8')] + + for variant, (card_one, card_two, expected) in enumerate(test_data, 1): + with self.subTest(f'variation #{variant}', card_one=card_one, card_two=card_two, expected=expected): + actual_result = higher_card(card_one, card_two) + error_msg = (f'Called higher_card({card_one}, {card_two}). ' + f'The function returned {actual_result}, ' + f'but the test expected {expected} as the result for the cards {card_one, card_two}.') + + self.assertEqual(actual_result, expected, msg=error_msg) + + @pytest.mark.task(taskno=3) + def test_value_of_ace(self): + test_data = [('2', '3', 11), ('3', '6', 11), ('5', '2', 11), + ('8', '2', 11), ('5', '5', 11), ('Q', 'A', 1), + ('10', '2', 1), ('7', '8', 1), ('J', '9', 1), + ('K', 'K', 1), ('2', 'A', 1), ('A', '2', 1)] + + for variant, (card_one, card_two, ace_value) in enumerate(test_data, 1): + with self.subTest(f'variation #{variant}', card_one=card_one, card_two=card_two, ace_value=ace_value): + actual_result = value_of_ace(card_one, card_two) + error_msg = (f'Called value_of_ace({card_one}, {card_two}). ' + f'The function returned {actual_result}, ' + f'but the test expected {ace_value} as the value of an ace card ' + f'when the hand includes {card_one, card_two}.') + + self.assertEqual(value_of_ace(card_one, card_two), ace_value, msg=error_msg) + + @pytest.mark.task(taskno=4) + def test_is_blackjack(self): + test_data = [(('A', 'K'), True), (('10', 'A'), True), + (('10', '9'), False), (('A', 'A'), False), + (('4', '7'), False), (('9', '2'), False), + (('Q', 'K'), False)] + + for variant, (hand, expected) in enumerate(test_data, 1): + with self.subTest(f'variation #{variant}', hand=hand, expected=expected): + actual_result = is_blackjack(*hand) + error_msg = (f'Called is_blackjack({hand[0]}, {hand[1]}). ' + f'The function returned {actual_result}, ' + f'but hand {hand} {"is" if expected else "is not"} a blackjack.') + + self.assertEqual(actual_result, expected, msg=error_msg) + + @pytest.mark.task(taskno=5) + def test_can_split_pairs(self): + test_data = [(('Q', 'K'), True), (('6', '6'), True), + (('A', 'A'), True),(('10', 'A'), False), + (('10', '9'), False)] + + for variant, (hand, expected) in enumerate(test_data, 1): + with self.subTest(f'variation #{variant}', input=hand, expected=expected): + actual_result = can_split_pairs(*hand) + error_msg = (f'Called can_split_pairs({hand[0]}, {hand[1]}). ' + f'The function returned {actual_result}, ' + f'but hand {hand} {"can" if expected else "cannot"} be split into pairs.') + + self.assertEqual(actual_result, expected, msg=error_msg) + + @pytest.mark.task(taskno=6) + def test_can_double_down(self): + test_data = [(('A', '9'), True), (('K', 'A'), True), + (('4', '5'), True),(('A', 'A'), False), + (('10', '2'), False), (('10', '9'), False)] + + for variant, (hand, expected) in enumerate(test_data, 1): + with self.subTest(f'variation #{variant}', hand=hand, expected=expected): + actual_result = can_double_down(*hand) + error_msg = (f'Called can_double_down({hand[0]}, {hand[1]}). ' + f'The function returned {actual_result}, ' + f'but hand {hand} {"can" if expected else "cannot"} be doubled down.') + + self.assertEqual(actual_result, expected, msg=error_msg) diff --git a/python/bob/.exercism/config.json b/python/bob/.exercism/config.json new file mode 100644 index 0000000..ec0fc61 --- /dev/null +++ b/python/bob/.exercism/config.json @@ -0,0 +1,47 @@ +{ + "authors": [], + "contributors": [ + "0xae", + "aldraco", + "atg-abhishek", + "austinlyons", + "behrtam", + "BethanyG", + "cmccandless", + "cypher", + "Dog", + "etrepum", + "ikhadykin", + "janetriley", + "jremmen", + "koljakube", + "kytrinyx", + "lowks", + "lucasdpau", + "miketamis", + "N-Parsons", + "patricksjackson", + "pheanex", + "sdublish", + "sjakobi", + "stonemirror", + "thenigan", + "thomasjpfan", + "tqa236", + "yawpitch" + ], + "files": { + "solution": [ + "bob.py" + ], + "test": [ + "bob_test.py" + ], + "example": [ + ".meta/example.py" + ] + }, + "blurb": "Bob is a lackadaisical teenager. In conversation, his responses are very limited.", + "source": "Inspired by the 'Deaf Grandma' exercise in Chris Pine's Learn to Program tutorial.", + "source_url": "https://pine.fm/LearnToProgram/?Chapter=06" +} diff --git a/python/bob/.exercism/metadata.json b/python/bob/.exercism/metadata.json new file mode 100644 index 0000000..c8b0a9a --- /dev/null +++ b/python/bob/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"bob","id":"c2728ecca3df4966b10c928d9fdc8a06","url":"https://exercism.org/tracks/python/exercises/bob","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/bob/HELP.md b/python/bob/HELP.md new file mode 100644 index 0000000..c92dfd6 --- /dev/null +++ b/python/bob/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +
+ +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit bob.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/bob/README.md b/python/bob/README.md new file mode 100644 index 0000000..823897d --- /dev/null +++ b/python/bob/README.md @@ -0,0 +1,72 @@ +# Bob + +Welcome to Bob on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Introduction + +Bob is a [lackadaisical][] teenager. +He likes to think that he's very cool. +And he definitely doesn't get excited about things. +That wouldn't be cool. + +When people talk to him, his responses are pretty limited. + +[lackadaisical]: https://www.collinsdictionary.com/dictionary/english/lackadaisical + +## Instructions + +Your task is to determine what Bob will reply to someone when they say something to him or ask him a question. + +Bob only ever answers one of five things: + +- **"Sure."** + This is his response if you ask him a question, such as "How are you?" + The convention used for questions is that it ends with a question mark. +- **"Whoa, chill out!"** + This is his answer if you YELL AT HIM. + The convention used for yelling is ALL CAPITAL LETTERS. +- **"Calm down, I know what I'm doing!"** + This is what he says if you yell a question at him. +- **"Fine. Be that way!"** + This is how he responds to silence. + The convention used for silence is nothing, or various combinations of whitespace characters. +- **"Whatever."** + This is what he answers to anything else. + +## Source + +### Contributed to by + +- @0xae +- @aldraco +- @atg-abhishek +- @austinlyons +- @behrtam +- @BethanyG +- @cmccandless +- @cypher +- @Dog +- @etrepum +- @ikhadykin +- @janetriley +- @jremmen +- @koljakube +- @kytrinyx +- @lowks +- @lucasdpau +- @miketamis +- @N-Parsons +- @patricksjackson +- @pheanex +- @sdublish +- @sjakobi +- @stonemirror +- @thenigan +- @thomasjpfan +- @tqa236 +- @yawpitch + +### Based on + +Inspired by the 'Deaf Grandma' exercise in Chris Pine's Learn to Program tutorial. - https://pine.fm/LearnToProgram/?Chapter=06 \ No newline at end of file diff --git a/python/bob/__pycache__/bob.cpython-313.pyc b/python/bob/__pycache__/bob.cpython-313.pyc new file mode 100644 index 0000000..1fcd1dc Binary files /dev/null and b/python/bob/__pycache__/bob.cpython-313.pyc differ diff --git a/python/bob/__pycache__/bob.cpython-314.pyc b/python/bob/__pycache__/bob.cpython-314.pyc new file mode 100644 index 0000000..349580e Binary files /dev/null and b/python/bob/__pycache__/bob.cpython-314.pyc differ diff --git a/python/bob/__pycache__/bob_test.cpython-313-pytest-8.3.4.pyc b/python/bob/__pycache__/bob_test.cpython-313-pytest-8.3.4.pyc new file mode 100644 index 0000000..4c52ca7 Binary files /dev/null and b/python/bob/__pycache__/bob_test.cpython-313-pytest-8.3.4.pyc differ diff --git a/python/bob/__pycache__/bob_test.cpython-314-pytest-9.1.0.pyc b/python/bob/__pycache__/bob_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..b55959a Binary files /dev/null and b/python/bob/__pycache__/bob_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/bob/bob.py b/python/bob/bob.py new file mode 100644 index 0000000..092f7b9 --- /dev/null +++ b/python/bob/bob.py @@ -0,0 +1,11 @@ +def response(hey_bob): + if hey_bob.strip() == "": + return "Fine. Be that way!" + elif hey_bob.strip().isupper() and hey_bob.strip()[-1] == "?": + return "Calm down, I know what I'm doing!" + elif hey_bob.strip()[-1] == "?": + return "Sure." + elif hey_bob.strip().isupper(): + return "Whoa, chill out!" + else: + return "Whatever." diff --git a/python/bob/bob_test.py b/python/bob/bob_test.py new file mode 100644 index 0000000..755d5c9 --- /dev/null +++ b/python/bob/bob_test.py @@ -0,0 +1,101 @@ +# These tests are auto-generated with test data from: +# https://github.com/exercism/problem-specifications/tree/main/exercises/bob/canonical-data.json +# File last updated on 2025-01-10 + +import unittest + +from bob import ( + response, +) + + +class BobTest(unittest.TestCase): + def test_stating_something(self): + self.assertEqual(response("Tom-ay-to, tom-aaaah-to."), "Whatever.") + + def test_shouting(self): + self.assertEqual(response("WATCH OUT!"), "Whoa, chill out!") + + def test_shouting_gibberish(self): + self.assertEqual(response("FCECDFCAAB"), "Whoa, chill out!") + + def test_asking_a_question(self): + self.assertEqual( + response("Does this cryogenic chamber make me look fat?"), "Sure." + ) + + def test_asking_a_numeric_question(self): + self.assertEqual(response("You are, what, like 15?"), "Sure.") + + def test_asking_gibberish(self): + self.assertEqual(response("fffbbcbeab?"), "Sure.") + + def test_talking_forcefully(self): + self.assertEqual(response("Hi there!"), "Whatever.") + + def test_using_acronyms_in_regular_speech(self): + self.assertEqual( + response("It's OK if you don't want to go work for NASA."), "Whatever." + ) + + def test_forceful_question(self): + self.assertEqual( + response("WHAT'S GOING ON?"), "Calm down, I know what I'm doing!" + ) + + def test_shouting_numbers(self): + self.assertEqual(response("1, 2, 3 GO!"), "Whoa, chill out!") + + def test_no_letters(self): + self.assertEqual(response("1, 2, 3"), "Whatever.") + + def test_question_with_no_letters(self): + self.assertEqual(response("4?"), "Sure.") + + def test_shouting_with_special_characters(self): + self.assertEqual( + response("ZOMG THE %^*@#$(*^ ZOMBIES ARE COMING!!11!!1!"), + "Whoa, chill out!", + ) + + def test_shouting_with_no_exclamation_mark(self): + self.assertEqual(response("I HATE THE DENTIST"), "Whoa, chill out!") + + def test_statement_containing_question_mark(self): + self.assertEqual(response("Ending with ? means a question."), "Whatever.") + + def test_non_letters_with_question(self): + self.assertEqual(response(":) ?"), "Sure.") + + def test_prattling_on(self): + self.assertEqual(response("Wait! Hang on. Are you going to be OK?"), "Sure.") + + def test_silence(self): + self.assertEqual(response(""), "Fine. Be that way!") + + def test_prolonged_silence(self): + self.assertEqual(response(" "), "Fine. Be that way!") + + def test_alternate_silence(self): + self.assertEqual(response("\t\t\t\t\t\t\t\t\t\t"), "Fine. Be that way!") + + def test_starting_with_whitespace(self): + self.assertEqual(response(" hmmmmmmm..."), "Whatever.") + + def test_ending_with_whitespace(self): + self.assertEqual( + response("Okay if like my spacebar quite a bit? "), "Sure." + ) + + def test_other_whitespace(self): + self.assertEqual(response("\n\r \t"), "Fine. Be that way!") + + def test_non_question_ending_with_whitespace(self): + self.assertEqual( + response("This is a statement ending with whitespace "), "Whatever." + ) + + def test_multiple_line_question(self): + self.assertEqual( + response("\nDoes this cryogenic chamber make\n me look fat?"), "Sure." + ) diff --git a/python/card-games/.exercism/config.json b/python/card-games/.exercism/config.json new file mode 100644 index 0000000..f7d39ca --- /dev/null +++ b/python/card-games/.exercism/config.json @@ -0,0 +1,24 @@ +{ + "authors": [ + "itamargal", + "isaacg", + "bethanyg" + ], + "contributors": [ + "valentin-p", + "pranasziaukas" + ], + "files": { + "solution": [ + "lists.py" + ], + "test": [ + "lists_test.py" + ], + "exemplar": [ + ".meta/exemplar.py" + ] + }, + "icon": "poker", + "blurb": "Learn about lists by tracking hands in card games." +} diff --git a/python/card-games/.exercism/metadata.json b/python/card-games/.exercism/metadata.json new file mode 100644 index 0000000..6a27ba3 --- /dev/null +++ b/python/card-games/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"card-games","id":"06eba203367748c4996e631edfe7d087","url":"https://exercism.org/tracks/python/exercises/card-games","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/card-games/HELP.md b/python/card-games/HELP.md new file mode 100644 index 0000000..7ff7fcc --- /dev/null +++ b/python/card-games/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +
+ +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit lists.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/card-games/HINTS.md b/python/card-games/HINTS.md new file mode 100644 index 0000000..3c10eca --- /dev/null +++ b/python/card-games/HINTS.md @@ -0,0 +1,47 @@ +# Hints + +## General + +## 1. Tracking Poker Rounds + +- Lists in Python may be [constructed][constructed] in multiple ways. +- This function should [return][return] a `list`. + +## 2. Keeping all Rounds in the Same Place + +- Sequence types such as `list` support [common operations][common sequence operations]. +- This function should [return][return] a `list`. + +## 3. Finding Prior Rounds + +- Sequence types such as `list` support a few [common operations][common sequence operations]. +- This function should [return][return] a `bool`. + +## 4. Averaging Card Values + +- To get the average, this function should count how many items are in the `list` and sum up their values. Then, return the sum divided by the count. + +## 5. Alternate Averages + +- Sequence types such as `list` support a few [common operations][common sequence operations]. +- To access an element, use the square brackets (`[]`) notation. +- Remember that the first element of the `list` is at index 0 from the **left-hand** side. +- In Python, negative indexing starts at -1 from the **right-hand** side. This means that you can find the last element of a `list` by using `[-1]`. +- Think about how you could reuse the code from the functions that you have already implemented. + +## 6. More Averaging Techniques + +- Sequence types such as `list` already support a few [common operations][common sequence operations]. +- Think about reusing the code from the functions that you just implemented. +- The slice syntax supports a _step value_ (`[::]`). + +## 7. Bonus Round Rules + +- Lists are _mutable_. Once a `list` is created, you can modify, delete or add any type of element you wish. +- Python provides a wide range of [ways to modify `lists`][ways to modify `lists`]. + + +[common sequence operations]: https://docs.python.org/3/library/stdtypes.html#sequence-types-list-tuple-range +[constructed]: https://docs.python.org/3/library/stdtypes.html#list +[return]: https://www.w3schools.com/python/ref_keyword_return.asp +[ways to modify `lists`]: https://realpython.com/python-lists-tuples/#lists-are-mutable \ No newline at end of file diff --git a/python/card-games/README.md b/python/card-games/README.md new file mode 100644 index 0000000..a8334e3 --- /dev/null +++ b/python/card-games/README.md @@ -0,0 +1,393 @@ +# Card Games + +Welcome to Card Games on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. +If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :) + +## Introduction + +A [`list`][list] is a mutable collection of items in _sequence_. +Like most collections (_see the built-ins [`tuple`][tuple], [`dict`][dict] and [`set`][set]_), lists can hold reference to any (or multiple) data type(s) - including other lists. +Like any [sequence][sequence type], items can be accessed via `0-based index` number from the left and `-1-based index` from the right. +Lists can be copied in whole or in part via [slice notation][slice notation] or `.copy()`. + +Lists support both [common][common sequence operations] and [mutable][mutable sequence operations] sequence operations such as `min()`/`max()`, `.index()`, `.append()` and `.reverse()`. +List elements can be iterated over using the `for item in ` construct. + `for index, item in enumerate()` can be used when both the element index and the element value are needed. + +Under the hood, `lists` are implemented as [dynamic arrays][dynamic array] -- similar to Java's [`ArrayList`][arraylist] type, and are most often used to store groups of similar data (_strings, numbers, sets etc._) of unknown length. +Lists are an extremely flexible and useful data structure and many built-in methods and operations in Python produce lists as their output. + + +## Construction + +A `list` can be declared as a _literal_ with square `[]` brackets and commas between elements: + + +```python +>>> no_elements = [] + +>>> no_elements +[] + +>>> one_element = ["Guava"] + +>>> one_element +['Guava'] + +>>> elements_separated_with_commas = ["Parrot", "Bird", 334782] + +>>> elements_separated_with_commas +['Parrot', 'Bird', 334782] +``` + +For readability, line breaks can be used when there are many elements or nested data structures within a `list`: + + +```python +>>> lots_of_entries = [ + "Rose", + "Sunflower", + "Poppy", + "Pansy", + "Tulip", + "Fuchsia", + "Cyclamen", + "Lavender" + ] + +>>> lots_of_entries +['Rose', 'Sunflower', 'Poppy', 'Pansy', 'Tulip', 'Fuchsia', 'Cyclamen', 'Lavender'] + +# Each data structure is on its own line to help clarify what they are. +>>> nested_data_structures = [ + {"fish": "gold", "monkey": "brown", "parrot": "grey"}, + ("fish", "mammal", "bird"), + ['water', 'jungle', 'sky'] + ] + +>>> nested_data_structures +[{'fish': 'gold', 'monkey': 'brown', 'parrot': 'grey'}, ('fish', 'mammal', 'bird'), ['water', 'jungle', 'sky']] +``` + +The `list()` constructor can be used empty or with an _iterable_ as an argument. + Elements in the iterable are cycled through by the constructor and added to the `list` in order: + + +```python +>>> no_elements = list() + +>>> no_elements +[] + +# The tuple is unpacked and each element is added. +>>> multiple_elements_from_tuple = list(("Parrot", "Bird", 334782)) + +>>> multiple_elements_from_tuple +['Parrot', 'Bird', 334782] + +# The set is unpacked and each element is added. +>>> multiple_elements_from_set = list({2, 3, 5, 7, 11}) + +>>> multiple_elements_from_set +[2, 3, 5, 7, 11] +``` + +Results when using a `list` constructor with a `string` or a `dict` may be surprising: + + +```python +# String elements (Unicode code points) are iterated through and added *individually*. +>>> multiple_elements_string = list("Timbuktu") + +>>> multiple_elements_string +['T', 'i', 'm', 'b', 'u', 'k', 't', 'u'] + +# Unicode separators and positioning code points are also added *individually*. +>>> multiple_code_points_string = list('अभ्यास') + +>>> multiple_code_points_string +['अ', 'भ', '्', 'य', 'ा', 'स'] + +# The iteration default for dictionaries is over the keys, so only key data is inserted into the list. +>>> source_data = {"fish": "gold", "monkey": "brown"} + +>>> multiple_elements_dict_1 = list(source_data) +['fish', 'monkey'] +``` + +Because the `list` constructor will only take _iterables_ (or nothing) as arguments, objects that are _not_ iterable will throw a type error. + Consequently, it is much easier to create a one-item `list` via the literal method. + +```python +# Numbers are not iterable, and so attempting to create a list with a number passed to the constructor fails. +>>> one_element = list(16) +Traceback (most recent call last): + File "", line 1, in +TypeError: 'int' object is not iterable + +# Tuples *are* iterable, so passing a one-element tuple to the constructor does work, but it's awkward +>>> one_element_from_iterable = list((16,)) + +>>> one_element_from_iterable +[16] +``` + +## Accessing elements + +Items inside lists (_as well as items in other sequence types `str` & `tuple`_) can be accessed via `0-based index` and _bracket notation_. + Indexes can be from **`left`** --> **`right`** (_starting at zero_) or **`right`** --> **`left`** (_starting at -1_). + + + + + + +
index from left ⟹






+ +| 0
👇🏾 | 1
👇🏾 | 2
👇🏾 | 3
👇🏾 | 4
👇🏾 | 5
👇🏾 | +|:--------: |:--------: |:--------: |:--------: |:--------: |:--------: | +| P | y | t | h | o | n | +| 👆🏾
-6 | 👆🏾
-5 | 👆🏾
-4 | 👆🏾
-3 | 👆🏾
-2 | 👆🏾
-1 | +





⟸ index from right
+ + +```python +>>> breakfast_foods = ["Oatmeal", "Fruit Salad", "Eggs", "Toast"] + +# Oatmeal is at index 0 or index -4. +>>> breakfast_foods[0] +'Oatmeal' + +>>> breakfast_foods[-4] +'Oatmeal' + +# Eggs are at index -2 or 2 +>>> breakfast_foods[-2] +'Eggs' + +>>> breakfast_foods[2] +'Eggs' + +# Toast is at -1 +>>> breakfast_foods[-1] +'Toast' +``` + +A section of the elements inside a `list` can be accessed via _slice notation_ (`[start:stop]`). + A _slice_ is defined as an element sequence at position `index`, such that `start <= index < stop`. + _Slicing_ returns a copy of the "sliced" items and does not modify the original `list`. + + +A `step` parameter can also be used `[start:stop:step]` to "skip over" or filter the `list` elements (_for example, a `step` of 2 will select every other element in the range_): + + +```python +>>> colors = ["Red", "Purple", "Green", "Yellow", "Orange", "Pink", "Blue", "Grey"] + +# If there is no step parameter, the step is assumed to be 1. +>>> middle_colors = colors[2:6] + +>>> middle_colors +['Green', 'Yellow', 'Orange', 'Pink'] + +# If the start or stop parameters are omitted, the slice will +# start at index zero, and will stop at the end of the list. +>>> primary_colors = colors[::3] + +>>> primary_colors +['Red', 'Yellow', 'Blue'] +``` + +## Working with lists + +The usage of the built-in `sum()` function on a list will return the sum of all the numbers in the list: + +```python +>>> number_list = [1, 2, 3, 4] +>>> sum(number_list) +10 +``` + +You can also get the _length_ of a list by using the `len()` function: + +```python +>>> long_list = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J"] +>>> len(long_list) +10 +``` + +Lists can be also combined in various ways: + +```python +# Using the plus + operator unpacks each list and creates a new list, but it is not efficient. +>>> new_via_concatenate = ["George", 5] + ["cat", "Tabby"] + +>>> new_via_concatenate +['George', 5, 'cat', 'Tabby'] + +# Likewise, using the multiplication operator * is the equivalent of using + n times. +>>> first_group = ["cat", "dog", "elephant"] +>>> multiplied_group = first_group * 3 + +>>> multiplied_group +['cat', 'dog', 'elephant', 'cat', 'dog', 'elephant', 'cat', 'dog', 'elephant'] +``` + +Lists supply an _iterator_, and can be looped through/over in the same manner as other _sequence types_. + +```python +# Looping through the list and printing out each element. +>>> colors = ["Orange", "Green", "Grey", "Blue"] + +>>> for item in colors: +... print(item) +... +Orange +Green +Grey +Blue +``` + +_For a more in-depth explanation, of `loops` and `iterators`, complete the `loops` concept._ + +[arraylist]: https://beginnersbook.com/2013/12/java-arraylist/ +[common sequence operations]: https://docs.python.org/3/library/stdtypes.html#common-sequence-operations +[dict]: https://docs.python.org/3/library/stdtypes.html#dict +[dynamic array]: https://en.wikipedia.org/wiki/Dynamic_array +[list]: https://docs.python.org/3/library/stdtypes.html#list +[mutable sequence operations]: https://docs.python.org/3/library/stdtypes.html#typesseq-mutable +[sequence type]: https://docs.python.org/3/library/stdtypes.html#sequence-types-list-tuple-range +[set]: https://docs.python.org/3/library/stdtypes.html#set +[slice notation]: https://docs.python.org/3/reference/expressions.html#slicings +[tuple]: https://docs.python.org/3/library/stdtypes.html#tuple + +## Instructions + +Elyse is really looking forward to playing some poker (and other card games) during her upcoming trip to Vegas. + Being a big fan of "self-tracking" she wants to put together some small functions that will help her with tracking tasks and has asked for your help thinking them through. + +## 1. Tracking Poker Rounds + +Elyse is especially fond of poker, and wants to track how many rounds she plays - and _which rounds_ those are. + Every round has its own number, and every table shows the round number currently being played. + Elyse chooses a table and sits down to play her first round. She plans on playing three rounds. + +Implement a function `get_rounds()` that takes the current round number and returns a single `list` with that round and the _next two_ that are coming up: + +```python +>>> get_rounds(27) +[27, 28, 29] +``` + +## 2. Keeping all Rounds in the Same Place + +Elyse played a few rounds at the first table, then took a break and played some more rounds at a second table ... but ended up with a different list for each table! + She wants to put the two lists together, so she can track all of the poker rounds in the same place. + +Implement a function `concatenate_rounds(, )` that takes two lists and returns a single `list` consisting of all the rounds in the first `list`, followed by all the rounds in the second `list`: + +```python +>>> concatenate_rounds([27, 28, 29], [35, 36]) +[27, 28, 29, 35, 36] +``` + +## 3. Finding Prior Rounds + +Talking about some of the prior Poker rounds, another player remarks how similarly two of them played out. + Elyse is not sure if she played those rounds or not. + +Implement a function `list_contains_round(, )` that takes two arguments, a list of rounds played and a round number. + The function will return `True` if the round is in the list of rounds played, `False` if not: + +```python +>>> list_contains_round([27, 28, 29, 35, 36], 29) +True + +>>> list_contains_round([27, 28, 29, 35, 36], 30) +False +``` + +## 4. Averaging Card Values + +Elyse wants to try out a new game called Black Joe. + It's similar to Black Jack - where your goal is to have the cards in your hand add up to a target value - but in Black Joe the goal is to get the _average_ of the card values to be 7. + The average can be found by summing up all the card values and then dividing that sum by the number of cards in the hand. + +Implement a function `card_average()` that will return the average value of a hand of Black Joe. + +```python +>>> card_average([5, 6, 7]) +6.0 +``` + +## 5. Alternate Averages + +In Black Joe, speed is important. Elyse is going to try and find a faster way of finding the average. + +She has thought of two ways of getting an _average-like_ number: + +- Take the average of the _first_ and _last_ number in the hand. +- Using the median (middle card) of the hand. + +Implement the function `approx_average_is_average()`, given `hand`, a list containing the values of the cards in your hand. + +Return `True` if either _one_ `or` _both_ of the, above named, strategies result in a number _equal_ to the _actual average_. + +Note: _The length of all hands are odd, to make finding a median easier._ + +```python +>>> approx_average_is_average([1, 2, 3]) +True + +>>> approx_average_is_average([2, 3, 4, 8, 8]) +True + +>>> approx_average_is_average([1, 2, 3, 5, 9]) +False +``` + +## 6. More Averaging Techniques + +Intrigued by the results of her averaging experiment, Elyse is wondering if taking the average of the cards at the _even_ positions versus the average of the cards at the _odd_ positions would give the same results. + Time for another test function! + +Implement a function `average_even_is_average_odd()` that returns a Boolean indicating if the average of the cards at even indexes is the same as the average of the cards at odd indexes. + +```python +>>> average_even_is_average_odd([1, 2, 3]) +True + +>>> average_even_is_average_odd([1, 2, 3, 4]) +False +``` + +## 7. Bonus Round Rules + +Every 11th hand in Black Joe is a bonus hand with a bonus rule: if the last card you draw is a Jack, you double its value. + +Implement a function `maybe_double_last()` that takes a hand and checks if the last card is a Jack (11). + If the last card **is** a Jack (11), double its value before returning the hand. + +```python +>>> hand = [5, 9, 11] +>>> maybe_double_last(hand) +[5, 9, 22] + +>>> hand = [5, 9, 10] +>>> maybe_double_last(hand) +[5, 9, 10] +``` + +## Source + +### Created by + +- @itamargal +- @isaacg +- @bethanyg + +### Contributed to by + +- @valentin-p +- @pranasziaukas \ No newline at end of file diff --git a/python/card-games/__pycache__/lists.cpython-313.pyc b/python/card-games/__pycache__/lists.cpython-313.pyc new file mode 100644 index 0000000..b08c9c8 Binary files /dev/null and b/python/card-games/__pycache__/lists.cpython-313.pyc differ diff --git a/python/card-games/__pycache__/lists.cpython-314.pyc b/python/card-games/__pycache__/lists.cpython-314.pyc new file mode 100644 index 0000000..10607bc Binary files /dev/null and b/python/card-games/__pycache__/lists.cpython-314.pyc differ diff --git a/python/card-games/__pycache__/lists_test.cpython-313-pytest-8.3.4.pyc b/python/card-games/__pycache__/lists_test.cpython-313-pytest-8.3.4.pyc new file mode 100644 index 0000000..9772193 Binary files /dev/null and b/python/card-games/__pycache__/lists_test.cpython-313-pytest-8.3.4.pyc differ diff --git a/python/card-games/__pycache__/lists_test.cpython-314-pytest-9.1.0.pyc b/python/card-games/__pycache__/lists_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..4c26607 Binary files /dev/null and b/python/card-games/__pycache__/lists_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/card-games/lists.py b/python/card-games/lists.py new file mode 100644 index 0000000..9f0afc3 --- /dev/null +++ b/python/card-games/lists.py @@ -0,0 +1,96 @@ +"""Functions for tracking poker hands and assorted card tasks. + +Python list documentation: https://docs.python.org/3/tutorial/datastructures.html +""" + + +def get_rounds(number): + """Create a list containing the current and next two round numbers. + + :param number: int - current round number. + :return: list - current round and the two that follow. + """ + return [number + next for next in range(0, 3)] + + +def concatenate_rounds(rounds_1, rounds_2): + """Concatenate two lists of round numbers. + + :param rounds_1: list - first rounds played. + :param rounds_2: list - second set of rounds played. + :return: list - all rounds played. + """ + new_list: list = [] + new_list.extend(rounds_1) + new_list.extend(rounds_2) + return new_list + + +def list_contains_round(rounds, number): + """Check if the list of rounds contains the specified number. + + :param rounds: list - rounds played. + :param number: int - round number. + :return: bool - was the round played? + """ + return number in rounds + + +def card_average(hand): + """Calculate and returns the average card value from the list. + + :param hand: list - cards in hand. + :return: float - average value of the cards in the hand. + """ + total: int = 0 + for card in hand: + total += card + return total / len(hand) + + +def approx_average_is_average(hand): + """Return if the (average of first and last card values) OR ('middle' card) == calculated average. + + :param hand: list - cards in hand. + :return: bool - does one of the approximate averages equal the `true average`? + """ + average_first_and_last: float = (hand[0] + hand[-1]) / 2 + middle_card: int = hand[len(hand) // 2] + return average_first_and_last == card_average(hand) or middle_card == card_average( + hand + ) + + +def average_even_is_average_odd(hand): + """Return if the (average of even indexed card values) == (average of odd indexed card values). + + :param hand: list - cards in hand. + :return: bool - are even and odd averages equal? + """ + total_even: float = 0.00 + count_even: int = 0 + total_odd: float = 0.00 + count_odd: int = 0 + for index, card in enumerate(hand): + if index % 2: + total_even += card + count_even += 1 + else: + total_odd += card + count_odd += 1 + return (total_even / count_even) == (total_odd / count_odd) + + +def maybe_double_last(hand): + """Multiply a Jack card value in the last index position by 2. + + :param hand: list - cards in hand. + :return: list - hand with Jacks (if present) value doubled. + """ + new_list: list = [] + for index, card in enumerate(hand): + if card == 11 and index == len(hand) - 1: + new_list.append(card * 2) + else: + new_list.append(card) + return new_list diff --git a/python/card-games/lists_test.py b/python/card-games/lists_test.py new file mode 100644 index 0000000..e550112 --- /dev/null +++ b/python/card-games/lists_test.py @@ -0,0 +1,137 @@ +import unittest +import pytest + +from lists import ( + get_rounds, + concatenate_rounds, + list_contains_round, + card_average, + approx_average_is_average, + average_even_is_average_odd, + maybe_double_last, +) + + +class CardGamesTest(unittest.TestCase): + + @pytest.mark.task(taskno=1) + def test_get_rounds(self): + + input_data = [0, 1, 10, 27, 99, 666] + result_data = [[0, 1, 2], [1, 2, 3], + [10, 11, 12], [27, 28, 29], + [99, 100, 101], [666, 667, 668]] + + for variant, (number, expected) in enumerate(zip(input_data, result_data), start=1): + with self.subTest(f'variation #{variant}', number=number, expected=expected): + actual_result = get_rounds(number) + error_message = (f'Called get_rounds({number}). ' + f'The function returned {actual_result}, ' + f'but the tests expected rounds {expected} ' + f'given the current round {number}.') + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=2) + def test_concatenate_rounds(self): + + input_data = [([], []), ([0, 1], []), ([], [1, 2]), + ([1], [2]), ([27, 28, 29], [35, 36]), + ([1, 2, 3], [4, 5, 6])] + + result_data = [[], [0, 1], [1, 2], [1, 2], + [27, 28, 29, 35, 36], + [1, 2, 3, 4, 5, 6]] + + for variant, ((rounds_1, rounds_2), expected) in enumerate(zip(input_data, result_data), start=1): + with self.subTest(f'variation #{variant}', rounds_1=rounds_1, rounds_2=rounds_2, expected=expected): + actual_result = concatenate_rounds(rounds_1, rounds_2) + error_message = (f'Called concatenate_rounds({rounds_1}, {rounds_2}). ' + f'The function returned {actual_result}, but the tests ' + f'expected {expected} as the concatenation ' + f'of {rounds_1} and {rounds_2}.') + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=3) + def test_list_contains_round(self): + + input_data = [([], 1), ([1, 2, 3], 0), + ([27, 28, 29, 35, 36], 30), + ([1], 1), ([1, 2, 3], 1), + ([27, 28, 29, 35, 36], 29)] + result_data = [False, False, False, True, True, True] + + for variant, ((rounds, round_number), expected) in enumerate(zip(input_data, result_data), start=1): + with self.subTest(f'variation #{variant}', rounds=rounds, round_number=round_number, expected=expected): + actual_result = list_contains_round(rounds, round_number) + error_message = (f'Called list_contains_round({rounds}, {round_number}). ' + f'The function returned {actual_result}, but round {round_number} ' + f'{"is" if expected else "is not"} in {rounds}.') + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=4) + def test_card_average(self): + + input_data = [[1], [5, 6, 7], [1, 2, 3, 4], [1, 10, 100]] + result_data = [1.0, 6.0, 2.5, 37.0] + + for variant, (hand, expected) in enumerate(zip(input_data, result_data), start=1): + with self.subTest(f'variation #{variant}', hand=hand, expected=expected): + actual_result = card_average(hand) + error_message = (f'Called card_average({hand}). ' + f'The function returned {actual_result}, but ' + f'the tests expected {expected} as the average of {hand}.') + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=5) + def test_approx_average_is_average(self): + + input_data = [[0, 1, 5], [3, 6, 9, 12, 150], [1, 2, 3, 5, 9], + [2, 3, 4, 7, 8], [1, 2, 3], [2, 3, 4], + [2, 3, 4, 8, 8], [1, 2, 4, 5, 8]] + + result_data = [False, False, False, False, True, True, True, True] + + for variant, (hand, expected) in enumerate(zip(input_data, result_data), start=1): + with self.subTest(f'variation #{variant}', hand=hand, expected=expected): + actual_result = approx_average_is_average(hand) + error_message = (f'Called approx_average_is_average({hand}). ' + f'The function returned {actual_result}, but ' + f'the hand {hand} {"does" if expected else "does not"} ' + f'yield the same approximate average.') + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=6) + def test_average_even_is_average_odd(self): + + input_data = [[5, 6, 8], [1, 2, 3, 4], [1, 2, 3], [5, 6, 7], [1, 3, 5, 7, 9]] + result_data = [False, False, True, True, True] + + for variant, (input_hand, expected) in enumerate(zip(input_data, result_data), start=1): + with self.subTest(f'variation #{variant}', input_hand=input_hand, expected=expected): + actual_result = average_even_is_average_odd(input_hand) + error_message = (f'Called average_even_is_average_odd({input_hand}). ' + f'The function returned {actual_result}, but ' + f'the hand {"does" if expected else "does not"} ' + f'yield the same odd-even average.') + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=7) + def test_maybe_double_last(self): + + input_data = [(1, 2, 11), (5, 9, 11), (5, 9, 10), (1, 2, 3), (1, 11, 8)] + result_data = [[1, 2, 22], [5, 9, 22], [5, 9, 10], [1, 2, 3], [1, 11, 8]] + + for variant, (hand, expected) in enumerate(zip(input_data, result_data), start=1): + with self.subTest(f'variation #{variant}', hand=list(hand), expected=expected): + actual_result = maybe_double_last(list(hand)) + error_message = (f'Called maybe_double_last({list(hand)}). ' + f'The function returned {actual_result}, but ' + f'the tests expected {expected} as the maybe-doubled version of {list(hand)}.') + + self.assertEqual(actual_result, expected, msg=error_message) diff --git a/python/cater-waiter/.exercism/config.json b/python/cater-waiter/.exercism/config.json new file mode 100644 index 0000000..89145f5 --- /dev/null +++ b/python/cater-waiter/.exercism/config.json @@ -0,0 +1,25 @@ +{ + "authors": [ + "bethanyg" + ], + "contributors": [ + "zepam" + ], + "files": { + "solution": [ + "sets.py" + ], + "test": [ + "sets_test.py" + ], + "exemplar": [ + ".meta/exemplar.py" + ], + "editor": [ + "sets_test_data.py", + "sets_categories_data.py" + ] + }, + "icon": "meetup", + "blurb": "Learn about sets by managing the menus and ingredients for your catering company's event." +} diff --git a/python/cater-waiter/.exercism/metadata.json b/python/cater-waiter/.exercism/metadata.json new file mode 100644 index 0000000..dab0bdd --- /dev/null +++ b/python/cater-waiter/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"cater-waiter","id":"4bfa6aa1746a4186ab33090d6f51b49e","url":"https://exercism.org/tracks/python/exercises/cater-waiter","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/cater-waiter/HELP.md b/python/cater-waiter/HELP.md new file mode 100644 index 0000000..c619054 --- /dev/null +++ b/python/cater-waiter/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +
+ +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit sets.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/cater-waiter/HINTS.md b/python/cater-waiter/HINTS.md new file mode 100644 index 0000000..c8b5c0b --- /dev/null +++ b/python/cater-waiter/HINTS.md @@ -0,0 +1,63 @@ +# Hints + +## General + +- [Sets][sets] are mutable, unordered collections with no duplicate elements. +- Sets can contain any data type, as long as all elements are [hashable][hashable]. +- Sets are [iterable][iterable]. +- Sets are most often used to quickly dedupe other collections or for membership testing. +- Sets also support mathematical operations like `union`, `intersection`, `difference`, and `symmetric difference` + +## 1. Clean up Dish Ingredients + +- The `set()` constructor can take any [iterable][iterable] as an argument. [concept: lists](/tracks/python/concepts/lists) are iterable. +- Remember: [concept: tuples](/tracks/python/concepts/tuples) can be formed using `(, )` or via the `tuple()` constructor. + +## 2. Cocktails and Mocktails + +- A `set` is _disjoint_ from another set if the two sets share no elements. +- The `set()` constructor can take any [iterable][iterable] as an argument. [concept: lists](/tracks/python/concepts/lists) are iterable. +- In Python, [concept: strings](/tracks/python/concepts/strings) can be concatenated with the `+` sign. + +## 3. Categorize Dishes + +- Using [concept: loops](/tracks/python/concepts/loops) to iterate through the available meal categories might be useful here. +- If all the elements of `` are contained within ``, then ` <= `. +- The method equivalent of `<=` is `.issubset()` +- [concept: tuples](/tracks/python/concepts/tuples) can contain any data type, including other tuples. Tuples can be formed using `(, )` or via the `tuple()` constructor. +- Elements within [concept: tuples](/tracks/python/concepts/tuples) can be accessed from the left using a 0-based index number, or from the right using a -1-based index number. +- The `set()` constructor can take any [iterable][iterable] as an argument. [concept: lists](/tracks/python/concepts/lists) are iterable. +- [concept: strings](/tracks/python/concepts/strings) can be concatenated with the `+` sign. + +## 4. Label Allergens and Restricted Foods + +- A set _intersection_ are the elements shared between `` and ``. +- The set method equivalent of `&` is `.intersection()` +- Elements within [concept: tuples](/tracks/python/concepts/tuples) can be accessed from the left using a 0-based index number, or from the right using a -1-based index number. +- The `set()` constructor can take any [iterable][iterable] as an argument. [concept: lists](/tracks/python/concepts/lists) are iterable. +- [concept: tuples](/tracks/python/concepts/tuples) can be formed using `(, )` or via the `tuple()` constructor. + +## 5. Compile a "Master List" of Ingredients + +- A set _union_ is where ` and `` are combined into a single `set` +- The set method equivalent of `|` is `.union()` +- Using [concept: loops](/tracks/python/concepts/loops) to iterate through the various dishes might be useful here. + +## 6. Pull out Appetizers for Passing on Trays + +- A set _difference_ is where the elements of `` are removed from ``, e.g. ` - `. +- The set method equivalent of `-` is `.difference()` +- The `set()` constructor can take any [iterable][iterable] as an argument. [concept: lists](/tracks/python/concepts/lists) are iterable. +- The [concept: list](/tracks/python/concepts/lists) constructor can take any [iterable][iterable] as an argument. Sets are iterable. + +## 7. Find Ingredients Used in Only One Recipe + +- A set _symmetric difference_ is where elements appear in `` or ``, but not **_both_** sets. +- A set _symmetric difference_ is the same as subtracting the `set` _intersection_ from the `set` _union_, e.g. `( | ) - ( & )` +- A _symmetric difference_ of more than two `sets` will include elements that are repeated more than two times across the input `sets`. To remove these cross-set repeated elements, the _intersections_ between set pairs needs to be subtracted from the symmetric difference. +- Using [concept: loops](/tracks/python/concepts/loops) to iterate through the various dishes might be useful here. + + +[hashable]: https://docs.python.org/3.7/glossary.html#term-hashable +[iterable]: https://docs.python.org/3/glossary.html#term-iterable +[sets]: https://docs.python.org/3/tutorial/datastructures.html#sets \ No newline at end of file diff --git a/python/cater-waiter/README.md b/python/cater-waiter/README.md new file mode 100644 index 0000000..abef763 --- /dev/null +++ b/python/cater-waiter/README.md @@ -0,0 +1,582 @@ +# Cater Waiter + +Welcome to Cater Waiter on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. +If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :) + +## Introduction + + +A [set][type-set] is a _mutable_ and _unordered_ collection of [_hashable_][hashable] objects. +Set members must be distinct — duplicate items are not allowed. +They can hold multiple different data types and even nested structures like a `tuple` of `tuples` — as long as all elements can be _hashed_. +Sets also come in an immutable [`frozensets`][type-frozenset] flavor. + +Sets are most commonly used to quickly remove duplicates from other data structures or item groupings. +They are also used for efficient comparisons when sequencing and duplicate tracking are not needed. + +Like other collection types (_dictionaries, lists, tuples_), `sets` support: +- Iteration via `for item in ` +- Membership checking via `in` and `not in`, +- Length calculation through `len()`, and +- Shallow copies through `copy()` + +`sets` do not support: +- Indexing of any kind +- Ordering via sorting or insertion +- Slicing +- Concatenation via `+` + + +Checking membership in a `set` has constant time complexity (on average) versus checking membership in a `list` or `string`, where the time complexity grows as the length of the data increases. +Methods such as `.union()`, `.intersection()`, or `.difference()` also have constant time complexity (on average). + + +## Set Literals + +A `set` can be directly entered as a _set literal_ with curly `{}` brackets and commas between elements. +Duplicates are silently omitted: + +```python +>>> one_element = {'😀'} +{'😀'} + +>>> multiple_elements = {'😀', '😃', '😄', '😁'} +{'😀', '😃', '😄', '😁'} + +>>> multiple_duplicates = {'Hello!', 'Hello!', 'Hello!', + '¡Hola!','Привіт!', 'こんにちは!', + '¡Hola!','Привіт!', 'こんにちは!'} +{'こんにちは!', '¡Hola!', 'Hello!', 'Привіт!'} +``` + +Set literals use the same curly braces as `dict` literals, which means you need to use `set()` to create an empty `set`. + + +## The Set Constructor + +`set()` (_the constructor for the `set` class_) can be used with any `iterable` passed as an argument. +Elements of the `iterable` are cycled through and added to the `set` individually. +Element order is not preserved and duplicates are silently omitted: + +```python +# To create an empty set, the constructor must be used. +>>> no_elements = set() +set() + +# The tuple is unpacked & each element is added. +# Duplicates are removed. +>>> elements_from_tuple = set(("Parrot", "Bird", + 334782, "Bird", "Parrot")) +{334782, 'Bird', 'Parrot'} + +# The list is unpacked & each element is added. +# Duplicates are removed. +>>> elements_from_list = set([2, 3, 2, 3, 3, 3, 5, + 7, 11, 7, 11, 13, 13]) +{2, 3, 5, 7, 11, 13} +``` + +### Gotchas when Creating Sets + +Due to its "unpacking" behavior, using `set()` with a string might be surprising: + +```python +# String elements (Unicode code points) are +# iterated through and added *individually*. +>>> elements_string = set("Timbuktu") +{'T', 'b', 'i', 'k', 'm', 't', 'u'} + +# Unicode separators and positioning code points +# are also added *individually*. +>>> multiple_code_points_string = set('अभ्यास') +{'अ', 'भ', 'य', 'स', 'ा', '्'} +``` + +Sets can hold different datatypes and _nested_ datatypes, but all `set` elements must be _hashable_: + +```python +# Attempting to use a list for a set member throws a TypeError +>>> lists_as_elements = {['😅','🤣'], + ['😂','🙂','🙃'], + ['😜', '🤪', '😝']} + +Traceback (most recent call last): + File "", line 1, in +TypeError: unhashable type: 'list' + + +# Standard sets are mutable, so they cannot be hashed. +>>> sets_as_elements = {{'😅','🤣'}, + {'😂','🙂','🙃'}, + {'😜', '🤪', '😝'}} + +Traceback (most recent call last): + File "", line 1, in +TypeError: unhashable type: 'set' +``` + + +## Working with Sets + +Sets have methods that generally mimic [mathematical set operations][mathematical-sets]. +Most (_not all_) of these methods have an [operator][operator] equivalent. +Methods generally take any `iterable` as an argument, while operators require that both sides of the operation are `sets` or `frozensets`. + + +### Disjoint Sets + +The `.isdisjoint()` method is used to test if a `sets` elements have any overlap with the elements of another `set`. +The method will accept any `iterable` or `set` as an argument. +It will return `True` if the two sets have **no elements in common**, `False` if elements are **shared**. +There is no operator equivalent: + + +```python +# Both mammals and additional_animals are lists. +>>> mammals = ['squirrel','dog','cat','cow', 'tiger', 'elephant'] +>>> additional_animals = ['pangolin', 'panda', 'parrot', + 'lemur', 'tiger', 'pangolin'] + +# Animals is a dict. +>>> animals = {'chicken': 'white', + 'sparrow': 'grey', + 'eagle': 'brown and white', + 'albatross': 'grey and white', + 'crow': 'black', + 'elephant': 'grey', + 'dog': 'rust', + 'cow': 'black and white', + 'tiger': 'orange and black', + 'cat': 'grey', + 'squirrel': 'black'} + +# Birds is a set. +>>> birds = {'crow','sparrow','eagle','chicken', 'albatross'} + +# Mammals and birds don't share any elements. +>>> birds.isdisjoint(mammals) +True + +# There are also no shared elements between +# additional_animals and birds. +>>> birds.isdisjoint(additional_animals) +True + +# Animals and mammals have shared elements. +# **Note** The first object needs to be a set or converted to a set +# since .isdisjoint() is a set method. +>>> set(animals).isdisjoint(mammals) +False +``` + + +### Subsets and Supersets + +`.issubset()` is used to check if every element in `` is also in ``. +The operator form is ` <= `: + + +```python +# Both mammals and additional_animals are lists. +>>> mammals = ['squirrel','dog','cat','cow', 'tiger', 'elephant'] +>>> additional_animals = ['pangolin', 'panda', 'parrot', + 'lemur', 'tiger', 'pangolin'] + +# Animals is a dict. +>>> animals = {'chicken': 'white', + 'sparrow': 'grey', + 'eagle': 'brown and white', + 'albatross': 'grey and white', + 'crow': 'black', + 'elephant': 'grey', + 'dog': 'rust', + 'cow': 'black and white', + 'tiger': 'orange and black', + 'cat': 'grey', + 'squirrel': 'black'} + +# Birds is a set. +>>> birds = {'crow','sparrow','eagle','chicken', 'albatross'} + +# Set methods will take any iterable as an argument. +# All members of birds are also members of animals. +>>> birds.issubset(animals) +True + +# All members of mammals also appear in animals. +# **Note** The first object needs to be a set or converted to a set +# since .issubset() is a set method. +>>> set(mammals).issubset(animals) +True + +# Both objects need to be sets to use a set operator +>>> birds <= set(mammals) +False + +# A set is always a loose subset of itself. +>>> set(additional_animals) <= set(additional_animals) +True +``` + +`.issuperset()` is the inverse of `.issubset()`. +It is used to check if every element in `` is also in ``. +The operator form is ` >= `: + + +```python +# All members of mammals also appear in animals. +# **Note** The first object needs to be a set or converted to a set +# since .issuperset() is a set method. +>>> set(animals).issuperset(mammals) +True + +# All members of animals do not show up as members of birds. +>>> birds.issuperset(animals) +False + +# Both objects need to be sets to use a set operator +>>> birds >= set(mammals) +False + +# A set is always a loose superset of itself. +>>> set(animals) >= set(animals) +True +``` + + +### Set Intersections + +`.intersection(*)` returns a new `set` with elements common to the original `set` and all `` (_in other words, the `set` where everything [intersects][intersection]_). +The operator version of this method is ` & & & ... `: + + +```python +>>> perennials = {'Annatto','Asafetida','Asparagus','Azalea', + 'Winter Savory', 'Broccoli','Curry Leaf','Fennel', + 'Kaffir Lime','Kale','Lavender','Mint','Oranges', + 'Oregano', 'Tarragon', 'Wild Bergamot'} + +>>> annuals = {'Corn', 'Zucchini', 'Sweet Peas', 'Marjoram', + 'Summer Squash', 'Okra','Shallots', 'Basil', + 'Cilantro', 'Cumin', 'Sunflower', 'Chervil', + 'Summer Savory'} + +>>> herbs = ['Annatto','Asafetida','Basil','Chervil','Cilantro', + 'Curry Leaf','Fennel','Kaffir Lime','Lavender', + 'Marjoram','Mint','Oregano','Summer Savory' + 'Tarragon','Wild Bergamot','Wild Celery', + 'Winter Savory'] + + +# Methods will take any iterable as an argument. +>>> perennial_herbs = perennials.intersection(herbs) +{'Annatto', 'Asafetida', 'Curry Leaf', 'Fennel', 'Kaffir Lime', + 'Lavender', 'Mint', 'Oregano', 'Wild Bergamot','Winter Savory'} + +# Operators require both groups be sets. +>>> annuals & set(herbs) + {'Basil', 'Chervil', 'Marjoram', 'Cilantro'} +``` + + +### Set Unions + +`.union(*)` returns a new `set` with elements from `` and all ``. +The operator form of this method is ` | | | ... | `: + + +```python +>>> perennials = {'Asparagus', 'Broccoli', 'Sweet Potato', 'Kale'} +>>> annuals = {'Corn', 'Zucchini', 'Sweet Peas', 'Summer Squash'} +>>> more_perennials = ['Radicchio', 'Rhubarb', + 'Spinach', 'Watercress'] + +# Methods will take any iterable as an argument. +>>> perennials.union(more_perennials) +{'Asparagus','Broccoli','Kale','Radicchio','Rhubarb', +'Spinach','Sweet Potato','Watercress'} + +# Operators require sets. +>>> set(more_perennials) | perennials +{'Asparagus', + 'Broccoli', + 'Kale', + 'Radicchio', + 'Rhubarb', + 'Spinach', + 'Sweet Potato', + 'Watercress'} +``` + + +### Set Differences + +`.difference(*)` returns a new `set` with elements from the original `` that are not in ``. +The operator version of this method is ` - - - ...`. + +```python +>>> berries_and_veggies = {'Asparagus', + 'Broccoli', + 'Watercress', + 'Goji Berries', + 'Goose Berries', + 'Ramps', + 'Walking Onions', + 'Blackberries', + 'Strawberries', + 'Rhubarb', + 'Kale', + 'Artichokes', + 'Currants'} + +>>> veggies = ('Asparagus', 'Broccoli', 'Watercress', 'Ramps', + 'Walking Onions', 'Rhubarb', 'Kale', 'Artichokes') + +# Methods will take any iterable as an argument. +>>> berries = berries_and_veggies.difference(veggies) +{'Blackberries','Currants','Goji Berries', + 'Goose Berries', 'Strawberries'} + +# Operators require sets. +>>> berries_and_veggies - berries +{'Artichokes','Asparagus','Broccoli','Kale', +'Ramps','Rhubarb','Walking Onions','Watercress'} +``` + + +`.symmetric_difference()` returns a new `set` that contains elements that are in `` OR ``, **but not in both**. +The operator version of this method is ` ^ `: + + +```python +>>> plants_1 = {'🌲','🍈','🌵', '🥑','🌴', '🥭'} +>>> plants_2 = ('🌸','🌴', '🌺', '🌲', '🌻', '🌵') + + +# Methods will take any iterable as an argument. +>>> fruit_and_flowers = plants_1.symmetric_difference(plants_2) +>>> fruit_and_flowers +{'🌸', '🌺', '🍈', '🥑', '🥭','🌻' } + + +# Operators require both groups be sets. +>>> fruit_and_flowers ^ plants_1 +{'🌲', '🌸', '🌴', '🌵','🌺', '🌻'} + +>>> fruit_and_flowers ^ plants_2 +{ '🥑', '🌴','🌲', '🌵', '🍈', '🥭'} +``` + +~~~~exercism/note + +A symmetric difference of more than two sets will result in a `set` that includes both the elements unique to each `set` AND elements shared between more than two sets in the series (_details in the Wikipedia article on [symmetric difference][symmetric_difference]_). + +To obtain only items unique to each `set` in the series, intersections between all 2-set combinations need to be aggregated in a separate step, and removed: + + +```python +>>> one = {'black pepper','breadcrumbs','celeriac','chickpea flour', + 'flour','lemon','parsley','salt','soy sauce', + 'sunflower oil','water'} + +>>> two = {'black pepper','cornstarch','garlic','ginger', + 'lemon juice','lemon zest','salt','soy sauce','sugar', + 'tofu','vegetable oil','vegetable stock','water'} + +>>> three = {'black pepper','garlic','lemon juice','mixed herbs', + 'nutritional yeast', 'olive oil','salt','silken tofu', + 'smoked tofu','soy sauce','spaghetti','turmeric'} + +>>> four = {'barley malt','bell pepper','cashews','flour', + 'fresh basil','garlic','garlic powder', 'honey', + 'mushrooms','nutritional yeast','olive oil','oregano', + 'red onion', 'red pepper flakes','rosemary','salt', + 'sugar','tomatoes','water','yeast'} + +>>> intersections = (one & two | one & three | one & four | + two & three | two & four | three & four) +... +{'black pepper','flour','garlic','lemon juice','nutritional yeast', +'olive oil','salt','soy sauce', 'sugar','water'} + +# The ^ operation will include some of the items in intersections, +# which means it is not a "clean" symmetric difference - there +# are overlapping members. +>>> (one ^ two ^ three ^ four) & intersections +{'black pepper', 'garlic', 'soy sauce', 'water'} + +# Overlapping members need to be removed in a separate step +# when there are more than two sets that need symmetric difference. +>>> (one ^ two ^ three ^ four) - intersections +... +{'barley malt','bell pepper','breadcrumbs', 'cashews','celeriac', + 'chickpea flour','cornstarch','fresh basil', 'garlic powder', + 'ginger','honey','lemon','lemon zest','mixed herbs','mushrooms', + 'oregano','parsley','red onion','red pepper flakes','rosemary', + 'silken tofu','smoked tofu','spaghetti','sunflower oil', 'tofu', + 'tomatoes','turmeric','vegetable oil','vegetable stock','yeast'} +``` + +[symmetric_difference]: https://en.wikipedia.org/wiki/Symmetric_difference +~~~~ + +[hashable]: https://docs.python.org/3.7/glossary.html#term-hashable +[intersection]: https://www.mathgoodies.com/lessons/sets/intersection +[mathematical-sets]: https://en.wikipedia.org/wiki/Set_theory#Basic_concepts_and_notation +[operator]: https://www.computerhope.com/jargon/o/operator.htm +[type-frozenset]: https://docs.python.org/3/library/stdtypes.html#frozenset +[type-set]: https://docs.python.org/3/library/stdtypes.html#set + +## Instructions + +You and your business partners operate a small catering company. You've just agreed to run an event for a local cooking club that features "club favorite" dishes. The club is inexperienced in hosting large events, and needs help with organizing, shopping, prepping and serving. You've decided to write some small Python scripts to speed the whole planning process along. + +## 1. Clean up Dish Ingredients + +The event recipes were added from various sources and their ingredients appear to have duplicate (_or more_) entries — you don't want to end up purchasing excess items! + Before the shopping and cooking can commence, each dish's ingredient list needs to be "cleaned". + +Implement the `clean_ingredients(, )` function that takes the name of a dish and a `list` of ingredients. + This function should return a `tuple` with the name of the dish as the first item, followed by the de-duped `set` of ingredients. + + +```python +>>> clean_ingredients('Punjabi-Style Chole', ['onions', 'tomatoes', 'ginger paste', 'garlic paste', 'ginger paste', 'vegetable oil', 'bay leaves', 'cloves', 'cardamom', 'cilantro', 'peppercorns', 'cumin powder', 'chickpeas', 'coriander powder', 'red chili powder', 'ground turmeric', 'garam masala', 'chickpeas', 'ginger', 'cilantro']) + +>>> ('Punjabi-Style Chole', {'garam masala', 'bay leaves', 'ground turmeric', 'ginger', 'garlic paste', 'peppercorns', 'ginger paste', 'red chili powder', 'cardamom', 'chickpeas', 'cumin powder', 'vegetable oil', 'tomatoes', 'coriander powder', 'onions', 'cilantro', 'cloves'}) +``` + +## 2. Cocktails and Mocktails + +The event is going to include both cocktails and "mocktails" - mixed drinks _without_ the alcohol. + You need to ensure that "mocktail" drinks are truly non-alcoholic and the cocktails do indeed _include_ alcohol. + +Implement the `check_drinks(, )` function that takes the name of a drink and a `list` of ingredients. + The function should return the name of the drink followed by "Mocktail" if the drink has no alcoholic ingredients, and drink name followed by "Cocktail" if the drink includes alcohol. + For the purposes of this exercise, cocktails will only include alcohols from the ALCOHOLS constant in `sets_categories_data.py`: + +```python +>>> from sets_categories_data import ALCOHOLS + +>>> check_drinks('Honeydew Cucumber', ['honeydew', 'coconut water', 'mint leaves', 'lime juice', 'salt', 'english cucumber']) +... +'Honeydew Cucumber Mocktail' + +>>> check_drinks('Shirley Tonic', ['cinnamon stick', 'scotch', 'whole cloves', 'ginger', 'pomegranate juice', 'sugar', 'club soda']) +... +'Shirley Tonic Cocktail' +``` + +## 3. Categorize Dishes + +The guest list includes diners with different dietary needs, and your staff will need to separate the dishes into Vegan, Vegetarian, Paleo, Keto, and Omnivore. + +Implement the `categorize_dish(, )` function that takes a dish name and a `set` of that dish's ingredients. +The function should return a string with the `dish name: ` (_which meal category the dish belongs to_). +All dishes will "fit" into one of the categories imported from `sets_categories_data.py` (VEGAN, VEGETARIAN, PALEO, KETO, or OMNIVORE). + +```python +>>> from sets_categories_data import VEGAN, VEGETARIAN, PALEO, KETO, OMNIVORE + + +>>> categorize_dish('Sticky Lemon Tofu', {'tofu', 'soy sauce', 'salt', 'black pepper', 'cornstarch', 'vegetable oil', 'garlic', 'ginger', 'water', 'vegetable stock', 'lemon juice', 'lemon zest', 'sugar'}) +... +'Sticky Lemon Tofu: VEGAN' + +>>> categorize_dish('Shrimp Bacon and Crispy Chickpea Tacos with Salsa de Guacamole', {'shrimp', 'bacon', 'avocado', 'chickpeas', 'fresh tortillas', 'sea salt', 'guajillo chile', 'slivered almonds', 'olive oil', 'butter', 'black pepper', 'garlic', 'onion'}) +... +'Shrimp Bacon and Crispy Chickpea Tacos with Salsa de Guacamole: OMNIVORE' +``` + +## 4. Label Allergens and Restricted Foods + +Some guests have allergies and additional dietary restrictions. +These ingredients need to be tagged/annotated for each dish so that they don't cause issues. + +Implement the `tag_special_ingredients()` function that takes a `tuple` with the dish name in the first position, and a `list` or `set` of ingredients for that dish in the second position. +Return the dish name followed by the `set` of ingredients that require a special note on the dish description. +Dish ingredients inside a `list` may or may not have duplicates. + For the purposes of this exercise, all allergens or special ingredients that need to be labeled are in the SPECIAL_INGREDIENTS constant imported from `sets_categories_data.py`. + +```python +>>> from sets_categories_data import SPECIAL_INGREDIENTS + +>>> tag_special_ingredients(('Ginger Glazed Tofu Cutlets', ['tofu', 'soy sauce', 'ginger', 'corn starch', 'garlic', 'brown sugar', 'sesame seeds', 'lemon juice'])) +... +('Ginger Glazed Tofu Cutlets', {'garlic','soy sauce','tofu'}) + +>>> tag_special_ingredients(('Arugula and Roasted Pork Salad', ['pork tenderloin', 'arugula', 'pears', 'blue cheese', 'pine nuts', 'balsamic vinegar', 'onions', 'black pepper'])) +... +('Arugula and Roasted Pork Salad', {'pork tenderloin', 'blue cheese', 'pine nuts', 'onions'}) +``` + +## 5. Compile a "Master List" of Ingredients + +In preparation for ordering and shopping, you'll need to compile a "master list" of ingredients for everything on the menu (_quantities to be filled in later_). + +Implement the `compile_ingredients()` function that takes a `list` of dishes and returns a set of all ingredients in all listed dishes. +Each individual dish is represented by its `set` of ingredients. + +```python +dishes = [ {'tofu', 'soy sauce', 'ginger', 'corn starch', 'garlic', 'brown sugar', 'sesame seeds', 'lemon juice'}, + {'pork tenderloin', 'arugula', 'pears', 'blue cheese', 'pine nuts', + 'balsamic vinegar', 'onions', 'black pepper'}, + {'honeydew', 'coconut water', 'mint leaves', 'lime juice', 'salt', 'english cucumber'}] + +>>> compile_ingredients(dishes) +... +{'arugula', 'brown sugar', 'honeydew', 'coconut water', 'english cucumber', 'balsamic vinegar', 'mint leaves', 'pears', 'pork tenderloin', 'ginger', 'blue cheese', 'soy sauce', 'sesame seeds', 'black pepper', 'garlic', 'lime juice', 'corn starch', 'pine nuts', 'lemon juice', 'onions', 'salt', 'tofu'} +``` + +## 6. Pull out Appetizers for Passing on Trays + +The hosts have given you a list of dishes they'd like prepped as "bite-sized" appetizers to be served on trays. + You need to pull these from the main list of dishes being prepared as larger servings. + +Implement the `separate_appetizers(, )` function that takes a `list` of dish names and a `list` of appetizer names. +The function should return the `list` of dish names with appetizer names removed. +Either the `` or `` `list` could contain duplicates and may require de-duping. + +```python +dishes = ['Avocado Deviled Eggs','Flank Steak with Chimichurri and Asparagus', 'Kingfish Lettuce Cups', + 'Grilled Flank Steak with Caesar Salad','Vegetarian Khoresh Bademjan','Avocado Deviled Eggs', + 'Barley Risotto','Kingfish Lettuce Cups'] + +appetizers = ['Kingfish Lettuce Cups','Avocado Deviled Eggs','Satay Steak Skewers', + 'Dahi Puri with Black Chickpeas','Avocado Deviled Eggs','Asparagus Puffs', + 'Asparagus Puffs'] + +>>> separate_appetizers(dishes, appetizers) +... +['Vegetarian Khoresh Bademjan', 'Barley Risotto', 'Flank Steak with Chimichurri and Asparagus', + 'Grilled Flank Steak with Caesar Salad'] +``` + +## 7. Find Ingredients Used in Only One Recipe + +Within each category (_Vegan, Vegetarian, Paleo, Keto, Omnivore_), you're going to pull out ingredients that appear in only one dish. +These "singleton" ingredients will be assigned a special shopper to ensure they're not forgotten in the rush to get everything else done. + +Implement the `singleton_ingredients(, )` function that takes a `list` of dishes and a `_INTERSECTIONS` constant for the same category. +Each dish is represented by a `set` of its ingredients. +Each `_INTERSECTIONS` is a `set` of ingredients that appear in more than one dish in the category. +Using set operations, your function should return a `set` of "singleton" ingredients (_ingredients appearing in only one dish in the category_). + +```python +from sets_categories_data import example_dishes, EXAMPLE_INTERSECTION + +>>> singleton_ingredients(example_dishes, EXAMPLE_INTERSECTION) +... +{'garlic powder', 'sunflower oil', 'mixed herbs', 'cornstarch', 'celeriac', 'honey', 'mushrooms', 'bell pepper', 'rosemary', 'parsley', 'lemon', 'yeast', 'vegetable oil', 'vegetable stock', 'silken tofu', 'tofu', 'cashews', 'lemon zest', 'smoked tofu', 'spaghetti', 'ginger', 'breadcrumbs', 'tomatoes', 'barley malt', 'red pepper flakes', 'oregano', 'red onion', 'fresh basil'} +``` + +## Source + +### Created by + +- @bethanyg + +### Contributed to by + +- @zepam \ No newline at end of file diff --git a/python/cater-waiter/__pycache__/sets.cpython-313.pyc b/python/cater-waiter/__pycache__/sets.cpython-313.pyc new file mode 100644 index 0000000..82c5862 Binary files /dev/null and b/python/cater-waiter/__pycache__/sets.cpython-313.pyc differ diff --git a/python/cater-waiter/__pycache__/sets.cpython-314.pyc b/python/cater-waiter/__pycache__/sets.cpython-314.pyc new file mode 100644 index 0000000..e208b60 Binary files /dev/null and b/python/cater-waiter/__pycache__/sets.cpython-314.pyc differ diff --git a/python/cater-waiter/__pycache__/sets_categories_data.cpython-313.pyc b/python/cater-waiter/__pycache__/sets_categories_data.cpython-313.pyc new file mode 100644 index 0000000..1e9ea7a Binary files /dev/null and b/python/cater-waiter/__pycache__/sets_categories_data.cpython-313.pyc differ diff --git a/python/cater-waiter/__pycache__/sets_categories_data.cpython-314.pyc b/python/cater-waiter/__pycache__/sets_categories_data.cpython-314.pyc new file mode 100644 index 0000000..682adad Binary files /dev/null and b/python/cater-waiter/__pycache__/sets_categories_data.cpython-314.pyc differ diff --git a/python/cater-waiter/__pycache__/sets_test.cpython-313-pytest-8.3.4.pyc b/python/cater-waiter/__pycache__/sets_test.cpython-313-pytest-8.3.4.pyc new file mode 100644 index 0000000..fa2c40a Binary files /dev/null and b/python/cater-waiter/__pycache__/sets_test.cpython-313-pytest-8.3.4.pyc differ diff --git a/python/cater-waiter/__pycache__/sets_test.cpython-314-pytest-9.1.0.pyc b/python/cater-waiter/__pycache__/sets_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..d694710 Binary files /dev/null and b/python/cater-waiter/__pycache__/sets_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/cater-waiter/__pycache__/sets_test_data.cpython-313.pyc b/python/cater-waiter/__pycache__/sets_test_data.cpython-313.pyc new file mode 100644 index 0000000..bc018d5 Binary files /dev/null and b/python/cater-waiter/__pycache__/sets_test_data.cpython-313.pyc differ diff --git a/python/cater-waiter/__pycache__/sets_test_data.cpython-314.pyc b/python/cater-waiter/__pycache__/sets_test_data.cpython-314.pyc new file mode 100644 index 0000000..b170314 Binary files /dev/null and b/python/cater-waiter/__pycache__/sets_test_data.cpython-314.pyc differ diff --git a/python/cater-waiter/sets.py b/python/cater-waiter/sets.py new file mode 100644 index 0000000..43ddca4 --- /dev/null +++ b/python/cater-waiter/sets.py @@ -0,0 +1,121 @@ +"""Functions for compiling dishes and ingredients for a catering company.""" + +from sets_categories_data import ( + VEGAN, + VEGETARIAN, + KETO, + PALEO, + OMNIVORE, + ALCOHOLS, + SPECIAL_INGREDIENTS, +) + + +def clean_ingredients(dish_name, dish_ingredients): + """Remove duplicates from `dish_ingredients`. + + :param dish_name: str - containing the dish name. + :param dish_ingredients: list - dish ingredients. + :return: tuple - containing (dish_name, ingredient set). + + This function should return a `tuple` with the name of the dish as the first item, + followed by the de-duped `set` of ingredients as the second item. + """ + return (dish_name, set(dish_ingredients)) + + +def check_drinks(drink_name, drink_ingredients): + """Append "Cocktail" (alcohol) or "Mocktail" (no alcohol) to `drink_name`, based on `drink_ingredients`. + + :param drink_name: str - name of the drink. + :param drink_ingredients: list - ingredients in the drink. + :return: str - drink_name appended with "Mocktail" or "Cocktail". + + The function should return the name of the drink followed by "Mocktail" (non-alcoholic) and drink + name followed by "Cocktail" (includes alcohol). + + """ + return drink_name + ( + " Cocktail" if ALCOHOLS.intersection( + drink_ingredients) else " Mocktail" + ) + + +def categorize_dish(dish_name, dish_ingredients): + """Categorize `dish_name` based on `dish_ingredients`. + + :param dish_name: str - dish to be categorized. + :param dish_ingredients: set - ingredients for the dish. + :return: str - the dish name appended with ": ". + + This function should return a string with the `dish name: ` (which meal category the dish belongs to). + `` can be any one of (VEGAN, VEGETARIAN, PALEO, KETO, or OMNIVORE). + All dishes will "fit" into one of the categories imported from `sets_categories_data.py` + + """ + category: str = "" + if dish_ingredients <= VEGAN: + category = ": VEGAN" + if dish_ingredients <= VEGETARIAN: + category = ": VEGETARIAN" + if dish_ingredients <= PALEO: + category = ": PALEO" + if dish_ingredients <= KETO: + category = ": KETO" + if dish_ingredients <= OMNIVORE: + category = ": OMNIVORE" + return dish_name + category + + +def tag_special_ingredients(dish): + """Compare `dish` ingredients to `SPECIAL_INGREDIENTS`. + + :param dish: tuple - of (dish name, list of dish ingredients). + :return: tuple - containing (dish name, dish special ingredients). + + Return the dish name followed by the `set` of ingredients that require a special note on the dish description. + For the purposes of this exercise, all allergens or special ingredients that need to be tracked are in the + SPECIAL_INGREDIENTS constant imported from `sets_categories_data.py`. + """ + return (dish[0], set(dish[1]).intersection(SPECIAL_INGREDIENTS)) + + +def compile_ingredients(dishes): + """Create a master list of ingredients. + + :param dishes: list - of dish ingredient sets. + :return: set - of ingredients compiled from `dishes`. + + This function should return a `set` of all ingredients from all listed dishes. + """ + return set().union(*dishes) + + +def separate_appetizers(dishes, appetizers): + """Determine which `dishes` are designated `appetizers` and remove them. + + :param dishes: list - of dish names. + :param appetizers: list - of appetizer names. + :return: list - of dish names that do not appear on appetizer list. + + The function should return the list of dish names with appetizer names removed. + Either list could contain duplicates and may require de-duping. + """ + return list(set(dishes).difference(set(appetizers))) + + +def singleton_ingredients(dishes, intersection): + """Determine which `dishes` have a singleton ingredient (an ingredient that only appears once across dishes). + + :param dishes: list - of ingredient sets. + :param intersection: constant - can be one of `_INTERSECTIONS` constants imported from `sets_categories_data.py`. + :return: set - containing singleton ingredients. + + Each dish is represented by a `set` of its ingredients. + + Each `_INTERSECTIONS` is an `intersection` of all dishes in the category. `` can be any one of: + (VEGAN, VEGETARIAN, PALEO, KETO, or OMNIVORE). + + The function should return a `set` of ingredients that only appear in a single dish. + """ + return set().union(*dishes).difference(intersection) diff --git a/python/cater-waiter/sets_categories_data.py b/python/cater-waiter/sets_categories_data.py new file mode 100644 index 0000000..dc3b1a6 --- /dev/null +++ b/python/cater-waiter/sets_categories_data.py @@ -0,0 +1,212 @@ +# pylint: disable-all +# flake8: noqa, +VEGAN = { + 'chives', 'nutritional yeast', 'tomato', 'orange zest', 'pareve puff pastry', 'cashews', 'tofu', + 'rice vinegar', 'black pepper', 'cardamom powder', 'mustard seeds', 'parev shortcrust pastry', + 'scallions', 'water', 'chinese eggplants', 'lemon juice', 'smoked paprika', 'cloves', 'basmati rice', + 'cayenne pepper', 'green onions', 'sunflower oil', 'mixed herbs', 'garlic paste', 'parsley', + 'fresh red chili', 'flour', 'garlic', 'oregano', 'green beans', 'harissa', 'brandy', 'fresh basil', + 'coriander', 'vinegar', 'thyme', 'coriander seeds', 'clove powder', 'pomegranate seeds', + 'sugar', 'yukon gold potato', 'sesame oil', 'cinnamon powder', 'butternut squash', 'allspice powder', + 'red pepper flakes', 'soy sauce', 'sesame seeds', 'cornstarch', 'mango powder', 'vegetable stock', + 'raisins', 'barley malt', 'olive oil', 'ground almonds', 'white rice', 'garlic powder', 'walnuts', + 'saffron powder', 'red chili powder', 'turmeric powder', 'spring onions', 'yeast', 'khmeli suneli', + 'peanuts', 'bulgur', 'cilantro', 'onion', 'calabash nutmeg', 'black-eyed peas', 'grains of selim', + 'zucchini', 'currants', 'spaghetti', 'figs', 'red bell pepper', 'lemon zest', 'ground turmeric', + 'chili flakes', 'chickpea flour', 'hing', 'slivered almonds', 'vegetable oil', 'serrano chili', + 'salt', 'yellow onions', 'salt', 'coriander powder', 'orange zest', 'garam masala', 'yellow onion', + 'smoked tofu', 'bell pepper', 'apples', 'brown sugar', 'coconut oil', 'orange juice', + 'sorghum stems', 'dried blueberries', 'tomato paste', 'curry leaves', 'vegetarian worcestershire sauce', + 'hot water', 'fresh ginger', 'firm tofu', 'eggplants', 'bell pepper', 'siracha', 'carrot', 'nigella seeds', + 'vegan butter', "za'atar", 'baking soda', 'brown sugar', 'dried cranberries', 'kosher salt', 'mangoes', + 'vegan unsweetened yoghurt', 'black peppercorn', 'vinegar', 'dill', 'barberries', 'honey', 'tomatoes', + 'yellow split peas', 'persian cucumber', 'turmeric', 'lemon', 'cumin', 'oil', 'mushrooms', 'spring onion', + 'pomegranate concentrate', 'cumin seeds', 'balsamic vinegar', 'ripe plantains', 'celeriac', 'breadcrumbs', + 'ginger', 'dried cherries', 'red onion', 'rosemary', 'chopped parsley', 'corn', 'cumin powder', 'pecans', + 'silken tofu', 'pomegranate molasses', 'carrot', 'corn flour', 'mashed potatoes' + } + + +VEGETARIAN = { + 'almonds', 'chives', 'limes', 'puff pastry', 'onion', 'cashews', 'red cabbage', 'red wine vinegar', + 'brussel sprouts', 'fresh corn', 'black pepper', 'lemon juice', 'roasted corn', 'eggs', + 'fresh cilantro leaves', 'shiitake mushrooms', 'sunflower oil', 'sage', 'dijon mustard', + 'blanched almonds', 'dates', 'flour', 'fresh pea tendrils', 'garlic', 'egg', 'green beans', + 'yukon gold potato', 'vermicelli noodles', 'onions', 'avocado', 'dried lasagna noodles', + 'thyme', 'cauliflower', 'basil', 'watercress', 'black beans', 'butternut squash', 'red thai chili', + 'masa', 'red chili', 'red onions', 'jalapeño chili', 'grated nutmeg', 'feta cheese', 'hazelnuts', + 'soy sauce', 'shallots', 'chipotle chili', 'vegetable bullion', 'fresh cherry tomatoes', 'olive oil', + 'milk', 'fresh cherry bocconcini', 'crema', 'marmite', 'walnuts', 'nutmeg', 'ricotta cheese', + 'chestnuts', 'mint leaves', 'lime juice', 'white wine', 'apples', 'pearl barley', 'cotija cheese', + 'zucchini', 'currants', 'leek', 'pomegranate', 'lemon zest', 'avocados', 'parmesan cheese', 'mint', + 'leeks', 'fresh artichoke hearts', 'vegetable oil', 'brazil nuts', 'red chili', 'sharp white cheddar', + 'salt', 'pepitas', 'green lentils', 'beets', 'celery', 'smoked tofu', 'fresh tomatoes', + 'puff pastry sheets', 'palm sugar', 'vegetarian fish sauce', 'oil marinated artichokes', 'hot water', + 'chickpeas', 'firm tofu', 'wombok', 'carrot', 'asparagus', 'bean sprouts', 'kosher salt', + 'pasilla chili', 'tomatillos', 'parmesan rind', 'pasta sheets', 'cream', 'butter', 'croutons', + 'lacinato kale', 'fresh or frozen fava beans', 'fresh pumpkin', 'honey', 'tomatoes', 'olives', + 'capers', 'pine nuts', 'lemon', 'cumin', 'ancho chili', 'fresh peas', 'spring roll wrappers', + 'balsamic vinegar', 'portobello mushrooms', 'breadcrumbs', 'blue cheese', 'red onion', + 'rosemary', 'pecans', 'carrot', 'corn flour', 'toasted peanuts' + } + +PALEO = { + 'cinnamon', 'chiles de árbol', 'chives', 'limes', 'allspice', 'zucchini', 'seranno chili', 'lemon zest', + 'apple cider vinegar', 'avocados', 'cashews', 'mango', 'cilantro leaves', 'pepitas', 'white chicken', + 'chipotles', 'black pepper', 'scallions', 'pumpkin puree', 'water', 'serrano chili', 'lemon juice', + 'smoked paprika', 'homemade apricot honey preserves', 'eggs', 'salt', 'flank steak', 'fresh cilantro leaves', + 'cider vinegar', 'cloves', 'purple sweet potato', 'coconut yogurt', 'green onions', 'tilapia', + 'yellow bell pepper', 'coconut oil', 'whole chicken', 'coconut oil', 'safflower oil', 'roma tomatoes', + 'fresh red chili', 'fresh thai chili', 'shrimp', 'garlic', 'onions', 'lime', 'avocado', 'fresh parsley', + 'cauliflower', 'shredded red cabbage', 'basil', 'baking soda', 'serrano chili', + 'cherry tomatoes', 'kale', 'bacon', 'kosher salt', 'mangoes', 'lacinato kale', 'shallots', 'pineapple', + 'chipotle chili', 'white vinegar', 'honey', 'tomatoes', 'homemade tamarind concentrate', + 'mexican oregano', 'olive oil', 'pine nuts', 'garlic powder', 'coconut flour', 'green bell pepper', + 'dried apricots', 'cumin', 'nutmeg', 'kosher salt', 'onions', 'mustard seed', 'lemons', 'lime zest', + 'ground cumin', 'almond butter', 'chili powder', 'lime juice', 'paleo mayonnaise', 'pork chops', + 'cilantro', 'onion', 'red bell pepper', 'paleo parmesan cheese', 'radishes', 'avocado oil', + 'dijon mustard', 'avocado mayonnaise', 'castelfranco radicchio', 'worcestershire sauce', 'treviso' + } + +KETO = { + 'cinnamon', 'avocado oil', 'chives', 'sriacha', 'almond flour', 'crunchy peanut butter', + 'cucumbers', 'cream cheese', 'red cabbage', 'red wine vinegar', 'brussel sprouts', 'black pepper', + 'cardamom powder', 'mustard seeds', 'scallions', 'kecap manis', 'lemon juice', 'eggs', 'tahini', + 'cloves', 'green onions', 'dijon mustard', 'garlic paste', 'watermelon radishes', 'parmesan', + 'parsley', 'star anise', 'fresh cucumber', 'fresh red chili', 'shrimp', 'garlic', 'oregano', + 'fennel bulb', 'harissa', 'dutch carrot', 'fresh basil', 'avocado', 'clove powder', 'coriander seeds', + 'thyme', 'fresh parsley', 'chicken', 'cauliflower', 'basil', 'watercress', 'cinnamon powder', + 'cherry tomatoes', 'soy sauce', 'sesame seeds', 'micro cilantro', 'mozzarella cheese', 'shallots', + 'mango powder', 'chipotle chili', 'olive oil', 'spinach', 'pink peppercorns', 'coconut flour', + 'salmon steaks', 'dark soy sauce', 'red chili powder', 'turmeric powder', 'spring onions', + 'lime juice', 'ginger garlic paste', 'pork chops', 'peanuts', 'dried fenugreek leaves', 'cilantro', + 'onion', 'salmon fillets', 'toasted buckwheat', 'whole small crimini mushrooms', 'caster sugar', + 'granny smith apples', 'green cabbage', 'apple cider vinegar', 'chili flakes', 'parmesan cheese', + 'hing', 'castelfranco radicchio', 'cilantro leaves', 'fresh greek yogurt', 'roasted chicken', 'ghee', + 'flaxmeal', 'flank steak', 'salt', 'coriander powder', 'boned chicken', 'red chili flakes', + 'garam masala', 'almond meal', 'peanut oil', 'tomato paste', 'oyster sauce', + 'curry leaves', 'fresh ginger', 'cardamom', 'radishes', 'little gem lettuce heads', + 'grilled king fish', 'carrot', 'cinnamon sticks', 'heavy cream', 'asparagus', 'nigella seeds', + 'light soy sauce', 'pork belly', 'green chili', 'mangoes', 'red and green thai chili', 'butter', + 'vinegar', 'dill', 'fish sauce', 'white vinegar', 'tomatoes', 'mirin', + 'avocado mayonnaise', 'turmeric', 'lemon', 'cumin', 'fennel seeds', 'lemon juice', 'salt', + 'roasted peanuts', 'ginger', 'red onion', 'rosemary', 'cumin powder', 'cashew nuts', 'pecans', + 'green chili','whole small crimini mushrooms', 'monk fruit', 'sour cream' + } + +OMNIVORE = { + 'clams', 'prawns', 'white wine vinegar', 'date syrup', 'limes', 'tomato', 'coriander', + 'black chickpeas', 'yellow bell pepper', 'black cardamom', 'baby squid', 'pepitas', + 'red cabbage', 'baby scallops', 'green cardamom', 'black pepper', 'chaat masala', 'water', + 'lemon juice', 'tahini', 'cloves', 'white pepper', 'fennel bulbs', 'tomato puree', + 'maggi cubes', 'couscous', 'yellow mustard', 'parsley', 'sriracha', 'roma tomatoes', + 'shrimp', 'garlic', 'oregano', 'chicken wings', 'yukon gold potato', 'harissa', 'onions', + 'avocado', 'thyme', 'chicken', 'sugar', 'flat-leaf parsley', 'celery seeds', 'cherry tomatoes', + 'mayonnaise', 'scallion chutney', 'red pepper flakes', 'hazelnuts', 'soy sauce', 'sesame seeds', + 'red snapper', 'white onion', 'vegetable bullion', 'marjoram', 'pani puri', 'olive oil', 'rice', + 'serrano chili', 'tamarind concentrate', 'lime juice', 'white wine', 'beef brisket', 'cilantro', + 'onion', 'crushed red pepper flakes', 'chiles de árbol', 'fresh mint', 'zucchini', 'red bell pepper', + 'yoghurt', 'apple cider vinegar', 'parmesan cheese', 'slivered almonds', 'whole-milk yogurt', + 'anchovy fillets', 'fresh ricotta', 'mint', 'chile manzano', 'roasted chicken', 'sea salt', + 'fresh thyme', 'vegetable oil', 'salt', 'mexican crema', 'celery', 'yellow onion', + 'worcestershire sauce', 'fresh tortillas', 'tomato paste', 'oranges', 'chickpeas', + 'scotch bonnet pepper', 'shelled large shrimp', 'mussels', 'summer squash', 'salsa', + 'garlic cloves', 'fish stock', 'bell pepper', 'green bell pepper', 'carrot', 'cinnamon sticks', + 'thin sev', 'brown sugar', 'baby carrot', 'bacon', 'kosher salt', 'bay leaves', 'anaheim chili', + 'oaxaca cheese', 'butter', 'vinegar', 'crab legs', 'white vinegar', 'honey', 'tomatoes', + 'green cabbage', 'toasted bread', 'turmeric', 'lemon', 'cumin', 'black peppercorns', 'poblano chili', + 'arborio risotto rice', 'fresh corn tortillas', 'balsamic vinegar', 'rhubarb', 'ginger', + 'guajillo chile', 'filo pastry', 'leg of lamb', 'red onion', 'chipotle adobo sauce', 'rosemary', + 'chili powder', 'beer', 'carrot' + } + +SPECIAL_INGREDIENTS = {'cream','bacon', 'garlic', 'baby scallops', 'mussels', 'baby squid', 'cashews', 'salmon fillets', + 'filo pastry', 'almonds', 'milk', 'blue cheese', 'clams', 'shrimp', 'tomato puree', 'chocolate', + 'honey', 'anchovy fillets', 'bulgur', 'prawns', 'parmesan cheese', 'fish', 'shelled large shrimp', + 'gluten', 'crab legs', 'feta cheese', 'whole-milk yogurt', 'crema', 'firm tofu', 'fish stock', + 'fresh ricotta', 'tomato paste', 'fresh cherry tomatoes', 'pork chops', 'eggs', 'greek yogurt', + 'hazelnuts', 'pecans', 'brie cheese', 'oaxaca cheese', 'yellow onion', 'whey', 'silken tofu', + 'toasted bread', 'parmesan', 'beef', 'tofu', 'flour', 'tomatoes', 'red onion', 'slivered almonds', + 'strawberries', 'onions', 'pine nuts', 'cherry tomatoes', 'soy sauce', 'oyster sauce', + 'mozzarella cheese', 'roma tomatoes', 'heavy cream', 'paneer', 'pork tenderloin', 'garlic cloves', + 'swiss cheese', 'grilled king fish', 'ground almonds', 'tilapia', 'sprint onion', 'couscous', + 'walnuts', 'semolina', 'yogurt', 'cotija cheese', 'oysters', 'spaghetti', 'cheddar cheese', + 'butter', 'lobster', 'smoked tofu', 'peanuts', 'ground pork', 'fresh cherry bocconcini', + 'pork belly', 'toasted peanuts', 'roasted peanuts' + } + +ALCOHOLS = {"whiskey", "whisky", "white rum", "dark rum", "bourbon", "rye", "scotch", "vodka", + "tequila", "gin", "dry vermouth", "sweet vermouth", "prosecco","aperol", "brandy", "mezcal", + "triple sec", "coffee liqueur", "almond liqueur", "champagne", "orange curacao", "rum" + } + + +VEGAN_INTERSECTIONS = {'brown sugar', 'carrot', 'sugar', 'vegetable stock', 'fresh ginger', 'nutritional yeast', + 'cayenne pepper', 'olive oil', 'lemon', 'ginger', 'red onion', 'pomegranate molasses', + 'onion', 'water', 'chickpea flour', 'orange zest', 'coconut oil', 'smoked paprika', + 'lemon zest', 'sunflower oil', 'orange juice', 'black pepper', 'cinnamon powder', + 'mushrooms', 'cloves', 'salt', 'oil', 'vegan butter', 'turmeric', 'tomato paste', + 'mustard seeds', 'bell pepper', 'rosemary', 'vinegar', 'tomatoes', 'flour', 'soy sauce', + 'lemon juice', 'garlic'} + +VEGETARIAN_INTERSECTIONS = {'carrot', 'milk', 'basil', 'green lentils', 'vegetable bullion', 'red onions', + 'balsamic vinegar', 'lemon', 'olive oil', 'butter', 'honey', 'red chili', + 'red onion', 'breadcrumbs', 'lemon zest', 'pepitas', 'black pepper', 'fresh peas', + 'salt', 'firm tofu', 'ricotta cheese', 'kosher salt', 'watercress', 'cream', + 'parmesan cheese', 'shallots', 'rosemary', 'sage', 'tomatoes', 'walnuts', + 'lemon juice', 'thyme', 'garlic', 'eggs', 'red wine vinegar'} + +PALEO_INTERSECTIONS = {'basil', 'olive oil', 'honey', 'pine nuts', 'baking soda', 'shrimp', 'cherry tomatoes', + 'coconut oil', 'cinnamon', 'lemon zest', 'cumin', 'black pepper', 'lime', 'salt', + 'zucchini', 'kosher salt', 'chipotle chili', 'eggs', 'coconut flour', 'avocado', + 'cauliflower', 'serrano chili', 'safflower oil', 'tomatoes', 'lemon juice', 'onions', + 'garlic'} + +KETO_INTERSECTIONS = {'fresh cucumber', 'red cabbage', 'olive oil', 'ginger', 'butter', 'dill', 'red onion', + 'monk fruit', 'cherry tomatoes', 'spring onions', 'lime juice', 'fish sauce', + 'sesame seeds', 'black pepper', 'salt', 'chives', 'asparagus', 'eggs', + 'avocado mayonnaise', 'rosemary', 'cauliflower', 'flank steak', 'lemon juice', + 'garlic'} + +OMNIVORE_INTERSECTIONS = {'mint', 'carrot', 'fresh mint', 'olive oil', 'lemon', 'ginger', 'butter', 'honey', + 'leg of lamb', 'red onion', 'bay leaves', 'tamarind concentrate', + 'worcestershire sauce', 'onion', 'lime juice', 'water', 'anchovy fillets', 'celery', + 'black pepper', 'cilantro', 'chili powder', 'salt', 'mayonnaise', 'garlic cloves', + 'kosher salt', 'white onion', 'turmeric', 'rosemary', 'vinegar', 'tomatoes', + 'sea salt', 'soy sauce', 'lemon juice', 'onions', 'thyme', 'garlic', 'avocado', + 'fresh corn tortillas', 'tomato paste'} + + +EXAMPLE_INTERSECTION = {'fresh red chili', 'sugar', 'nutritional yeast', 'fresh ginger', 'red chili powder', 'garlic', + 'olive oil', 'mashed potatoes', 'garam masala', 'clove powder', 'cumin powder', 'onion', + 'chickpea flour', 'water', 'turmeric powder', 'hing', 'black pepper', 'cinnamon powder', + 'cilantro', 'salt', 'oil', 'cardamom powder', 'turmeric', 'garlic paste', 'mustard seeds', + 'vinegar', 'mangoes', 'nigella seeds', 'serrano chili', 'flour', 'soy sauce', 'coriander seeds', + 'coriander powder', 'lemon juice', 'mango powder', 'curry leaves'} + +example_dishes = [ + {'salt', 'breadcrumbs', 'water', 'flour', 'celeriac', 'chickpea flour', 'soy sauce', 'parsley', + 'sunflower oil', 'lemon', 'black pepper'}, + + {'cornstarch', 'salt', 'vegetable oil', 'sugar', 'vegetable stock', 'water', 'tofu', 'soy sauce', + 'lemon zest', 'lemon juice', 'black pepper', 'ginger', 'garlic'}, + + {'salt', 'mixed herbs', 'silken tofu', 'smoked tofu', 'nutritional yeast', 'turmeric', 'soy sauce', + 'garlic', 'lemon juice', 'olive oil', 'black pepper', 'spaghetti'}, + + {'salt', 'mushrooms', 'sugar', 'barley malt', 'nutritional yeast', 'fresh basil', 'olive oil', + 'honey', 'yeast', 'red onion', 'bell pepper', 'cashews', 'oregano', 'rosemary', 'garlic powder', + 'tomatoes', 'water', 'flour', 'red pepper flakes', 'garlic'}, + + {'mango powder', 'oil', 'salt', 'cardamom powder', 'fresh red chili', 'sugar', 'fresh ginger', + 'turmeric', 'red chili powder', 'curry leaves', 'garlic paste', 'mustard seeds', 'vinegar', + 'mashed potatoes', 'garam masala', 'mangoes', 'nigella seeds', 'clove powder', 'serrano chili', + 'cumin powder', 'onion', 'water', 'chickpea flour', 'coriander seeds', 'turmeric powder', 'hing', + 'coriander powder', 'cinnamon powder', 'cilantro', 'garlic'}, + + {'mango powder', 'oil', 'salt', 'cardamom powder', 'fresh red chili', 'sugar', 'fresh ginger', + 'turmeric', 'red chili powder', 'curry leaves', 'garlic paste', 'mustard seeds', 'vinegar', + 'mashed potatoes', 'garam masala', 'mangoes', 'nigella seeds', 'clove powder', 'serrano chili', + 'cumin powder', 'onion', 'water', 'chickpea flour', 'coriander seeds', 'turmeric powder', 'hing', + 'coriander powder', 'cinnamon powder', 'cilantro', 'garlic'} + ] diff --git a/python/cater-waiter/sets_test.py b/python/cater-waiter/sets_test.py new file mode 100644 index 0000000..ec93507 --- /dev/null +++ b/python/cater-waiter/sets_test.py @@ -0,0 +1,119 @@ +import unittest +import pytest + +# pylint: disable=deprecated-module +from sets import (clean_ingredients, + check_drinks, + categorize_dish, + tag_special_ingredients, + compile_ingredients, + separate_appetizers, + singleton_ingredients) + + +from sets_categories_data import (VEGAN, + VEGETARIAN, + KETO, + PALEO, + OMNIVORE, + ALCOHOLS, + SPECIAL_INGREDIENTS, + VEGAN_INTERSECTIONS, + VEGETARIAN_INTERSECTIONS, + PALEO_INTERSECTIONS, + KETO_INTERSECTIONS, + OMNIVORE_INTERSECTIONS) + +from sets_test_data import (recipes_with_duplicates, + recipes_without_duplicates, + all_drinks, + drink_names, + dishes_categorized, + dishes_to_special_label, + dishes_labeled, + ingredients_only, + dishes_and_appetizers, + dishes_cleaned, + dishes_and_overlap, + singletons) + + +class SetsTest(unittest.TestCase): + + @pytest.mark.task(taskno=1) + def test_clean_ingredients(self): + test_data = zip(recipes_with_duplicates[::3], recipes_without_duplicates[::3]) + + for variant, (item, result) in enumerate(test_data, start=1): + with self.subTest(f"variation #{variant}", inputs="recipes with duplicated ingredients", + result="recipe ingredients de-duped"): + + error_msg = (f"Expected the ingredient list for {item[0]} to be de-duplicated, " + "but the ingredients were not cleaned as expected.") + + self.assertEqual(clean_ingredients(item[0], item[1]), (result[1], result[2]), msg=error_msg) + + @pytest.mark.task(taskno=2) + def test_check_drinks(self): + test_data = zip(all_drinks[::2], drink_names[::2]) + + for variant, (item, result) in enumerate(test_data, start=1): + with self.subTest(f"variation #{variant}", iputs="all drinks", results="drinks classified"): + + error_msg = f"Expected {result} for {item}, but got something else instead." + self.assertEqual(check_drinks(item[0], item[1]), (result), msg=error_msg) + + @pytest.mark.task(taskno=3) + def test_categorize_dish(self): + test_data = zip(sorted(recipes_without_duplicates, reverse=True)[::3], dishes_categorized[::3]) + + for variant, (item, result) in enumerate(test_data, start=1): + with self.subTest(f"variation #{variant}", inputs="all recipes list", results="categorized dishes"): + + error_message = f"Expected category {result} for {item[0]}, but got a different category instead." + self.assertEqual(categorize_dish(item[1], item[2]), (result), msg=error_message) + + @pytest.mark.task(taskno=4) + def test_tag_special_ingredients(self): + test_data = zip(dishes_to_special_label[::3], dishes_labeled[::3]) + + for variant, (item, result) in enumerate(test_data, start=1): + with self.subTest(f"variation #{variant}", inputs="all recipes list", results="special ingredients tagged"): + + error_message = f"Expected {result} for {item}, but got something else instead." + self.assertEqual(tag_special_ingredients(item), (result), msg=error_message) + + @pytest.mark.task(taskno=5) + def test_compile_ingredients(self): + test_data = zip(ingredients_only, [VEGAN, VEGETARIAN, PALEO, KETO, OMNIVORE]) + + for variant, (item, result) in enumerate(test_data, start=1): + with self.subTest(f"variation #{variant}", inputs="all ingredients for all recipes", + result="combined list of ingredients for all dishes"): + + error_message = "Expected a proper set of combined ingredients, but something went wrong." + self.assertEqual(compile_ingredients(item), (result), msg=error_message) + + @pytest.mark.task(taskno=6) + def test_separate_appetizers(self): + test_data = zip(dishes_and_appetizers, dishes_cleaned) + + for variant, (item, result) in enumerate(test_data, start=1): + with self.subTest(f"variation #{variant}", inputs="dishes with appetizers", results="appetizers only"): + + error_message = "Expected only appetizers returned, but some dishes remain in the group." + result_type_error = f"You returned {type(separate_appetizers(item[0], item[1]))}, but a list was expected." + self.assertIsInstance(separate_appetizers(item[0], item[1]), list, msg=result_type_error) + self.assertEqual(sorted(separate_appetizers(item[0], item[1])), (sorted(result)), msg=error_message) + + @pytest.mark.task(taskno=7) + def test_singleton_ingredients(self): + test_data = zip(dishes_and_overlap, singletons) + + for variant, (item, result) in enumerate(test_data, start=1): + with self.subTest(f"variation #{variant}", inputs="overlapping ingredients", + results="ingredients in only one dish"): + + error_message = ("Expected only ingredients that belong to exactly " + "one dish, but got multi-dish ingredients instead.") + self.assertEqual(singleton_ingredients(item[0], item[1]), (result), msg=error_message) diff --git a/python/cater-waiter/sets_test_data.py b/python/cater-waiter/sets_test_data.py new file mode 100644 index 0000000..23a8ccd --- /dev/null +++ b/python/cater-waiter/sets_test_data.py @@ -0,0 +1,459 @@ +# pylint: disable-all +# flake8: noqa, +from sets_categories_data import (VEGAN_INTERSECTIONS, + VEGETARIAN_INTERSECTIONS, + PALEO_INTERSECTIONS, + KETO_INTERSECTIONS, + OMNIVORE_INTERSECTIONS) + + +################################### +# Data for test_clean_ingredients # +################################### + +recipes_with_duplicates = [('Kisir with Warm Pita', ['bulgur', 'pomegranate molasses', 'chopped parsley', 'lemon juice', 'tomato', 'persian cucumber', 'tomato paste', 'spring onion', 'water', 'olive oil', 'bulgur', 'bulgur', 'pomegranate molasses', 'pomegranate molasses', 'pomegranate molasses', 'chopped parsley', 'lemon juice', 'tomato', 'tomato', 'persian cucumber', 'tomato paste', 'tomato paste', 'tomato paste']), + ('Shakshuka', ['vegan unsweetened yoghurt', 'yellow onion', 'firm tofu', 'smoked paprika', 'tomatoes', 'tomato paste', 'sugar', 'cloves', 'cumin', "za'atar", 'olive oil', 'harissa', 'red bell pepper']), + ('Vegetarian Khoresh Bademjan', ['yellow split peas', 'tomato paste', 'black pepper', 'pomegranate concentrate', 'yellow onions', 'slivered almonds', 'ground turmeric', 'barberries', 'basmati rice', 'lemon juice', 'hot water', 'cayenne pepper', 'chinese eggplants', 'salt', 'orange juice', 'saffron powder', 'vegan butter', 'orange zest', 'kosher salt', 'yellow split peas', 'yellow split peas', 'tomato paste', 'tomato paste', 'tomato paste', 'black pepper']), + ('Baked Kelewele', ['smoked paprika', 'black peppercorn', 'red onion', 'grains of selim', 'cayenne pepper', 'calabash nutmeg', 'coconut oil', 'cloves', 'fresh ginger', 'salt', 'ripe plantains', 'smoked paprika', 'black peppercorn', 'black peppercorn', 'red onion', 'grains of selim', 'grains of selim', 'grains of selim']), + ('Waakye', ['baking soda', 'sorghum stems', 'coconut oil', 'black-eyed peas', 'water', 'salt', 'white rice', 'baking soda', 'baking soda', 'sorghum stems', 'sorghum stems', 'sorghum stems', 'coconut oil']), + ('Georgian Eggplant Rolls with Walnuts', ['pomegranate seeds', 'oil', 'coriander', 'garlic', 'khmeli suneli', 'eggplants', 'black pepper', 'vinegar', 'walnuts', 'water', 'salt']), + ('Burmese Tofu with Garlic, Ginger and Chili Sauce', ['soy sauce', 'oil', 'chili flakes', 'garlic', 'brown sugar', 'ginger', 'peanuts', 'rice vinegar', 'spring onions', 'water', 'turmeric', 'salt', 'chickpea flour', 'soy sauce', 'soy sauce', 'oil', 'oil', 'oil', 'chili flakes', 'garlic', 'brown sugar', 'brown sugar', 'ginger', 'peanuts', 'peanuts', 'peanuts']), + ('Celeriac Schnitzel', ['soy sauce', 'parsley', 'lemon', 'sunflower oil', 'black pepper', 'celeriac', 'breadcrumbs', 'water', 'salt', 'flour', 'chickpea flour']), + ('Sticky Lemon Tofu', ['soy sauce', 'vegetable stock', 'tofu', 'cornstarch', 'lemon juice', 'lemon zest', 'garlic', 'ginger', 'black pepper', 'sugar', 'water', 'salt', 'vegetable oil', 'soy sauce', 'soy sauce', 'vegetable stock', 'vegetable stock', 'vegetable stock', 'tofu']), + ('Vegan Carbonara', ['soy sauce', 'smoked tofu', 'lemon juice', 'nutritional yeast', 'mixed herbs', 'garlic', 'black pepper', 'silken tofu', 'turmeric', 'salt', 'olive oil', 'spaghetti', 'soy sauce', 'smoked tofu', 'smoked tofu', 'lemon juice', 'nutritional yeast', 'nutritional yeast', 'nutritional yeast']), + ('Vegan Pizza with Caramelized Onions', ['mushrooms', 'rosemary', 'garlic', 'red pepper flakes', 'yeast', 'barley malt', 'water', 'olive oil', 'garlic powder', 'oregano', 'honey', 'nutritional yeast', 'red onion', 'tomatoes', 'cashews', 'sugar', 'bell pepper', 'flour', 'salt', 'fresh basil', 'mushrooms', 'mushrooms', 'rosemary', 'rosemary', 'rosemary', 'garlic']), + ('Cheela with Spicy Mango Chutney', ['clove powder', 'oil', 'cinnamon powder', 'nigella seeds', 'curry leaves', 'coriander seeds', 'garlic', 'mangoes', 'mashed potatoes', 'cardamom powder', 'vinegar', 'water', 'mustard seeds', 'coriander powder', 'cumin powder', 'mango powder', 'garam masala', 'red chili powder', 'hing', 'garlic paste', 'turmeric powder', 'cilantro', 'sugar', 'onion', 'serrano chili', 'fresh ginger', 'turmeric', 'salt', 'fresh red chili', 'chickpea flour']), + ('Sweet and Spicy Crispy Green Beans', ['soy sauce', 'pomegranate molasses', 'sesame oil', 'green beans', 'sunflower oil', 'scallions', 'garlic', 'carrot', 'ginger', 'sesame seeds', 'tomato paste', 'bell pepper', 'siracha', 'soy sauce', 'soy sauce', 'pomegranate molasses', 'pomegranate molasses', 'pomegranate molasses', 'sesame oil', 'green beans', 'sunflower oil', 'sunflower oil', 'scallions', 'garlic', 'garlic', 'garlic']), + ('Vegan Mini Savory Mince Pies', ['mushrooms', 'cinnamon powder', 'rosemary', 'corn flour', 'ginger', 'brown sugar', 'carrot', 'black pepper', 'raisins', 'butternut squash', 'vegetarian worcestershire sauce', 'parev shortcrust pastry', 'olive oil', 'vegetable stock', 'dried cherries', 'lemon juice', 'lemon zest', 'figs', 'dried cranberries', 'apples', 'pecans', 'onion', 'orange juice', 'currants', 'dried blueberries', 'salt', 'brandy', 'orange zest', 'allspice powder']), + ('Roasted Corn and Zucchini Salad', ['green onions', 'lemon juice', 'lemon zest', 'dill', 'corn', 'tomatoes', 'black pepper', 'zucchini', 'olive oil', 'green onions', 'green onions', 'lemon juice', 'lemon juice', 'lemon juice', 'lemon zest']), + ('Golden Potato Salad', ['mustard seeds', 'cumin seeds', 'lemon juice', 'garlic', 'black pepper', 'balsamic vinegar', 'yukon gold potato', 'chives', 'turmeric', 'salt', 'olive oil', 'mustard seeds', 'cumin seeds', 'cumin seeds', 'lemon juice', 'garlic', 'garlic', 'garlic']), + ('Carrot Puff Pastry Tart', ['olive oil', 'lemon', 'lemon juice', 'pareve puff pastry', 'brown sugar', 'red onion', 'carrot', 'garlic', 'black pepper', 'thyme', 'vegan butter', 'water', 'salt', 'ground almonds', 'olive oil', 'olive oil', 'lemon', 'lemon', 'lemon', 'lemon juice']), + + ('Mushroom Lasagna', ['nutmeg', 'garlic', 'black pepper', 'onions', 'butter', 'parmesan cheese', 'portobello mushrooms', 'flour', 'dried lasagna noodles', 'olive oil', 'milk', 'kosher salt']), + ('Nut Wellington', ['sage', 'puff pastry sheets', 'hazelnuts', 'almonds', 'black pepper', 'thyme', 'marmite', 'breadcrumbs', 'walnuts', 'dates', 'eggs', 'olive oil', 'brazil nuts', 'leeks', 'chestnuts', 'cashews', 'apples', 'pecans', 'butter', 'salt', 'sage', 'sage', 'puff pastry sheets', 'puff pastry sheets', 'puff pastry sheets', 'hazelnuts', 'almonds', 'black pepper', 'black pepper', 'thyme', 'marmite', 'marmite', 'marmite']), + ('White Cheddar Scalloped Potatoes', ['shallots', 'garlic', 'cream', 'thyme', 'breadcrumbs', 'sharp white cheddar', 'yukon gold potato', 'milk', 'kosher salt']), + ('Winter Cobb Salad', ['smoked tofu', 'shiitake mushrooms', 'red wine vinegar', 'garlic', 'tomatoes', 'black pepper', 'avocados', 'blue cheese', 'onion', 'lacinato kale', 'eggs', 'olive oil', 'smoked tofu', 'smoked tofu', 'shiitake mushrooms', 'shiitake mushrooms', 'shiitake mushrooms', 'red wine vinegar']), + ('Roast Pumpkin and Lentil Salad with Roasted Lemon Dressing', ['honey', 'lemon', 'dijon mustard', 'feta cheese', 'red wine vinegar', 'red onion', 'watercress', 'green lentils', 'currants', 'capers', 'pepitas', 'fresh pumpkin', 'olive oil', 'honey', 'lemon', 'lemon', 'dijon mustard', 'feta cheese', 'feta cheese', 'feta cheese']), + ('Cambodian-Style Vegetable Spring Rolls', ['lime juice', 'toasted peanuts', 'firm tofu', 'garlic', 'corn flour', 'bean sprouts', 'carrot', 'palm sugar', 'shallots', 'red chili', 'vermicelli noodles', 'wombok', 'soy sauce', 'sunflower oil', 'spring roll wrappers', 'vegetarian fish sauce', 'lime juice', 'lime juice', 'toasted peanuts', 'toasted peanuts', 'toasted peanuts', 'firm tofu']), + ('Summer Minestrone Cups', ['fresh peas', 'rosemary', 'garlic', 'chickpeas', 'carrot', 'leek', 'green lentils', 'red chili', 'olive oil', 'croutons', 'fresh corn', 'lemon zest', 'green beans', 'parmesan rind', 'basil', 'tomatoes', 'vegetable bullion', 'parmesan cheese', 'celery', 'mint']), + ('Fried Zucchini with Balsamic and Chili Dressing', ['honey', 'lemon juice', 'garlic', 'red onion', 'red thai chili', 'pomegranate', 'balsamic vinegar', 'mint leaves', 'zucchini', 'olive oil', 'honey', 'honey', 'lemon juice', 'lemon juice', 'lemon juice', 'garlic', 'red onion', 'red thai chili', 'red thai chili', 'pomegranate', 'balsamic vinegar', 'balsamic vinegar', 'balsamic vinegar']), + ('Barley Risotto', ['sage', 'beets', 'pearl barley', 'brussel sprouts', 'rosemary', 'garlic', 'carrot', 'red onion', 'black pepper', 'thyme', 'butternut squash', 'vegetable bullion', 'parmesan cheese', 'olive oil', 'white wine']), + ('Cherry Tomato, Watercress and Fava Bean Salad', ['fresh peas', 'fresh cherry tomatoes', 'garlic', 'watercress', 'balsamic vinegar', 'fresh or frozen fava beans', 'fresh cherry bocconcini', 'salt', 'olive oil', 'fresh peas', 'fresh peas', 'fresh cherry tomatoes', 'fresh cherry tomatoes', 'fresh cherry tomatoes', 'garlic']), + ('Fresh Garden Peas over Cauliflower Almond Puree', ['red onions', 'lemon', 'fresh peas', 'garlic', 'grated nutmeg', 'cream', 'cauliflower', 'blanched almonds', 'fresh pea tendrils', 'olive oil', 'vegetable oil', 'red onions', 'lemon', 'lemon', 'fresh peas', 'garlic', 'garlic', 'garlic']), + ('Walnut Ravioli with Artichokes and Tomatoes', ['pine nuts', 'oil marinated artichokes', 'olives', 'rosemary', 'fresh tomatoes', 'ricotta cheese', 'black pepper', 'fresh artichoke hearts', 'walnuts', 'pasta sheets', 'lemon juice', 'lemon zest', 'basil', 'red onion', 'butter', 'salt', 'pine nuts', 'pine nuts', 'oil marinated artichokes', 'oil marinated artichokes', 'oil marinated artichokes', 'olives']), + ('Asparagus Puffs', ['eggs', 'asparagus', 'lemon juice', 'red onion', 'ricotta cheese', 'black pepper', 'thyme', 'salt', 'parmesan cheese', 'puff pastry', 'chives']), + ('Grilled Tofu Tacos', ['cotija cheese', 'masa', 'fresh cilantro leaves', 'jalapeño chili', 'chipotle chili', 'firm tofu', 'garlic', 'carrot', 'roasted corn', 'tomatillos', 'pepitas', 'ancho chili', 'crema', 'red onions', 'pasilla chili', 'lemon', 'hot water', 'lemon juice', 'tomatoes', 'avocado', 'cumin', 'red cabbage', 'limes', 'black beans', 'cotija cheese', 'cotija cheese', 'masa', 'masa', 'masa', 'fresh cilantro leaves', 'jalapeño chili', 'chipotle chili', 'chipotle chili', 'firm tofu', 'garlic', 'garlic', 'garlic']), + + ('Zucchini Fritters with Lemon-Thyme Coconut Yogurt', ['baking soda', 'coconut flour', 'lemon juice', 'lemon zest', 'eggs', 'coconut yogurt', 'black pepper', 'fresh thai chili', 'coconut oil', 'chives', 'zucchini', 'salt']), + ('Avocado Deviled Eggs', ['lime juice', 'fresh cilantro leaves', 'eggs', 'seranno chili', 'avocado', 'pepitas', 'salt', 'garlic powder', 'lime juice', 'lime juice', 'fresh cilantro leaves', 'fresh cilantro leaves', 'fresh cilantro leaves', 'eggs']), + ('Grilled Flank Steak with Caesar Salad', ['pine nuts', 'white vinegar', 'chipotle chili', 'scallions', 'garlic', 'paleo parmesan cheese', 'black pepper', 'avocado oil', 'treviso', 'olive oil', 'radishes', 'flank steak', 'dijon mustard', 'castelfranco radicchio', 'worcestershire sauce', 'fresh parsley', 'cherry tomatoes', 'salt', 'avocado mayonnaise', 'pine nuts', 'white vinegar', 'white vinegar', 'chipotle chili', 'scallions', 'scallions', 'scallions']), + ('Pumpkin Bread Crostini', ['coconut flour', 'garlic', 'black pepper', 'cloves', 'eggs', 'olive oil', 'onions', 'honey', 'apple cider vinegar', 'almond butter', 'baking soda', 'nutmeg', 'pumpkin puree', 'cinnamon', 'shrimp', 'basil', 'coconut oil', 'cherry tomatoes', 'salt', 'fresh red chili', 'coconut flour', 'coconut flour', 'garlic', 'garlic', 'garlic', 'black pepper']), + ('BLT Bites', ['mustard seed', 'onion', 'kale', 'cherry tomatoes', 'bacon', 'paleo mayonnaise']), + ('Roasted Chicken with Roasted Tomatoes, Avocado, and Sweet Potatoes', ['purple sweet potato', 'chiles de árbol', 'garlic', 'tomatoes', 'safflower oil', 'black pepper', 'mexican oregano', 'avocados', 'shallots', 'cumin', 'olive oil', 'lemons', 'whole chicken', 'limes', 'kosher salt', 'purple sweet potato', 'purple sweet potato', 'chiles de árbol', 'chiles de árbol', 'chiles de árbol', 'garlic', 'tomatoes', 'safflower oil', 'safflower oil', 'black pepper', 'mexican oregano', 'mexican oregano', 'mexican oregano']), + ('Chicken with Tamarind and Apricot Sauce', ['garlic', 'black pepper', 'dried apricots', 'roma tomatoes', 'water', 'olive oil', 'honey', 'cinnamon', 'ground cumin', 'cider vinegar', 'chili powder', 'safflower oil', 'homemade tamarind concentrate', 'white chicken', 'allspice', 'chipotles', 'salt', 'homemade apricot honey preserves', 'kosher salt']), + ('Grilled Fish Tacos with Cauliflower Tortillas', ['green onions', 'serrano chili', 'shredded red cabbage', 'smoked paprika', 'mango', 'eggs', 'black pepper', 'cilantro', 'cauliflower', 'avocado', 'lime', 'cumin', 'salt', 'tilapia', 'green onions', 'green onions', 'serrano chili', 'serrano chili', 'serrano chili', 'shredded red cabbage']), + ('Grilled Pork Chops with Mango Pineapple Salsa', ['cilantro leaves', 'lime', 'pineapple', 'chipotle chili', 'garlic', 'mangoes', 'cauliflower', 'avocado', 'serrano chili', 'pork chops', 'lime zest', 'lacinato kale', 'onions', 'cilantro leaves', 'lime', 'lime', 'pineapple', 'chipotle chili', 'chipotle chili', 'chipotle chili']), + ('Grilled Shrimp and Pesto over Zucchini Noodles', ['pine nuts', 'shrimp', 'green bell pepper', 'lemon juice', 'basil', 'lemon zest', 'garlic', 'tomatoes', 'cashews', 'yellow bell pepper', 'cumin', 'zucchini', 'salt', 'olive oil', 'red bell pepper', 'pine nuts', 'pine nuts', 'shrimp', 'shrimp', 'shrimp', 'green bell pepper']), + + ('Cauliflower Pizza with Roasted Tomatoes and Chicken', ['parmesan', 'almond meal', 'rosemary', 'mozzarella cheese', 'roasted chicken', 'tomato paste', 'cauliflower', 'cherry tomatoes', 'eggs', 'fresh basil', 'olive oil']), + ('Flank Steak with Chimichurri and Asparagus', ['white vinegar', 'asparagus', 'flank steak', 'chipotle chili', 'scallions', 'garlic', 'black pepper', 'cauliflower', 'sour cream', 'fresh parsley', 'salt', 'olive oil', 'white vinegar', 'white vinegar', 'asparagus', 'asparagus', 'asparagus', 'flank steak', 'chipotle chili', 'scallions', 'scallions', 'garlic', 'black pepper', 'black pepper', 'black pepper']), + ('Kingfish Lettuce Cups', ['soy sauce', 'watermelon radishes', 'lime juice', 'fish sauce', 'mirin', 'little gem lettuce heads', 'peanut oil', 'garlic', 'sesame seeds', 'oyster sauce', 'spring onions', 'avocado', 'grilled king fish', 'red cabbage']), + ('Butter Chicken with Grilled Mushrooms, Brussel Sprouts and Mango Chutney', ['clove powder', 'curry leaves', 'coriander seeds', 'ginger', 'cardamom powder', 'vinegar', 'mustard seeds', 'mango powder', 'garam masala', 'red chili powder', 'chicken', 'hing', 'turmeric powder', 'tomatoes', 'ginger garlic paste', 'fresh greek yogurt', 'fresh ginger', 'monk fruit', 'turmeric', 'cashew nuts', 'salt', 'fresh red chili', 'cinnamon powder', 'nigella seeds', 'whole small crimini mushrooms', 'brussel sprouts', 'garlic', 'mangoes', 'heavy cream', 'cloves', 'coriander powder', 'cumin powder', 'cardamom', 'green chili', 'cinnamon', 'garlic paste', 'red chili flakes', 'lemon juice', 'cilantro', 'butter', 'dried fenugreek leaves', 'boned chicken', 'clove powder', 'clove powder', 'curry leaves', 'curry leaves', 'curry leaves', 'coriander seeds']), + ('Prawn and Herb Omelette', ['green onions', 'parsley', 'sesame seeds', 'black pepper', 'chives', 'eggs', 'fennel bulb', 'tahini', 'olive oil', 'harissa', 'shrimp', 'lemon juice', 'dill', 'butter', 'onion', 'fresh cucumber', 'monk fruit', 'salt', 'green onions', 'parsley', 'parsley', 'sesame seeds', 'black pepper', 'black pepper', 'black pepper']), + ('Satay Steak Skewers', ['sriacha', 'apple cider vinegar', 'lime juice', 'fish sauce', 'red and green thai chili', 'flank steak', 'carrot', 'peanuts', 'cucumbers', 'roasted peanuts', 'crunchy peanut butter', 'kecap manis', 'monk fruit', 'micro cilantro', 'olive oil', 'sriacha', 'sriacha', 'apple cider vinegar', 'apple cider vinegar', 'apple cider vinegar', 'lime juice']), + ('Parmesan Crackers and Spinach Crackers with Salmon Pate', ['spinach', 'parmesan cheese', 'coconut flour', 'chili flakes', 'garlic', 'black pepper', 'cream cheese', 'ghee', 'lemon juice', 'flaxmeal', 'red onion', 'salt', 'salmon fillets', 'pecans', 'almond flour', 'cumin', 'fresh cucumber', 'cherry tomatoes', 'chives', 'avocado mayonnaise']), + ('Pork Chops with Grilled Castelfranco Radicchio and Asparagus', ['rosemary', 'garlic', 'black pepper', 'thyme', 'avocado oil', 'eggs', 'oregano', 'asparagus', 'lemon', 'dijon mustard', 'basil', 'castelfranco radicchio', 'dill', 'butter', 'pork chops', 'monk fruit', 'salt', 'avocado mayonnaise', 'rosemary', 'rosemary', 'garlic', 'garlic', 'garlic', 'black pepper', 'thyme', 'avocado oil', 'avocado oil', 'eggs', 'oregano', 'oregano', 'oregano']), + ('Seared Salmon with Pickled Vegetable and Watercress Salad', ['lime juice', 'caster sugar', 'toasted buckwheat', 'lemon juice', 'red wine vinegar', 'red onion', 'dutch carrot', 'salmon steaks', 'watercress', 'pink peppercorns', 'shallots', 'fennel seeds', 'red cabbage', 'radishes']), + ('Braised Pork Belly with Apple Salad', ['cilantro leaves', 'green cabbage', 'lemon juice', 'pork belly', 'dark soy sauce', 'granny smith apples', 'ginger', 'light soy sauce', 'sesame seeds', 'black pepper', 'cinnamon sticks', 'spring onions', 'star anise', 'monk fruit', 'olive oil', 'cilantro leaves', 'cilantro leaves', 'green cabbage', 'green cabbage', 'green cabbage', 'lemon juice']), + + ('Beachside Snapper', ['lime juice', 'salsa', 'green bell pepper', 'anaheim chili', 'black pepper', 'olive oil', 'yellow mustard', 'red bell pepper', 'soy sauce', 'mexican crema', 'mayonnaise', 'white onion', 'garlic cloves', 'fresh corn tortillas', 'red onion', 'tomatoes', 'limes', 'worcestershire sauce', 'butter', 'yellow bell pepper', 'salt', 'red snapper', 'lime juice', 'salsa', 'salsa', 'green bell pepper', 'anaheim chili', 'anaheim chili', 'anaheim chili']), + ('Governor Shrimp Tacos', ['lime juice', 'poblano chili', 'tomato paste', 'black pepper', 'chipotle adobo sauce', 'chile manzano', 'roma tomatoes', 'pepitas', 'oaxaca cheese', 'white onion', 'shelled large shrimp', 'garlic cloves', 'fresh corn tortillas', 'red onion', 'worcestershire sauce', 'avocado', 'butter', 'kosher salt', 'lime juice', 'lime juice', 'poblano chili', 'poblano chili', 'poblano chili', 'tomato paste']), + ('Shrimp, Bacon and Crispy Chickpea Tacos with Salsa de Guacamole', ['fresh tortillas', 'shrimp', 'garlic', 'chickpeas', 'black pepper', 'slivered almonds', 'guajillo chile', 'bacon', 'sea salt', 'butter', 'onion', 'avocado', 'olive oil']), + ('Burnt Masala Wings with Classic Coleslaw', ['lime juice', 'green cabbage', 'chiles de árbol', 'green cardamom', 'ginger', 'carrot', 'sriracha', 'black pepper', 'cinnamon sticks', 'celery seeds', 'cloves', 'black cardamom', 'olive oil', 'chicken wings', 'apple cider vinegar', 'mayonnaise', 'honey', 'black peppercorns', 'lemon juice', 'garlic cloves', 'tamarind concentrate', 'cilantro', 'butter', 'serrano chili', 'red cabbage', 'kosher salt', 'lime juice', 'lime juice', 'green cabbage', 'green cabbage', 'green cabbage', 'chiles de árbol', 'green cardamom', 'ginger', 'ginger', 'carrot', 'sriracha', 'sriracha', 'sriracha']), + ('Dahi Puri with Black Chickpeas', ['whole-milk yogurt', 'chaat masala', 'ginger', 'pani puri', 'scallion chutney', 'yukon gold potato', 'black chickpeas', 'thin sev', 'date syrup', 'red onion', 'roasted chicken', 'chili powder', 'tamarind concentrate', 'cumin', 'turmeric', 'mint']), + ('Brisket with Grilled Rhubarb, Onions, and Fennel', ['white vinegar', 'parsley', 'yellow onion', 'rhubarb', 'garlic', 'brown sugar', 'black pepper', 'thyme', 'crushed red pepper flakes', 'fennel bulbs', 'beer', 'marjoram', 'vegetable oil', 'soy sauce', 'oregano', 'lemon', 'red onion', 'chili powder', 'cilantro', 'beef brisket', 'balsamic vinegar', 'worcestershire sauce', 'celery', 'mint', 'kosher salt', 'white vinegar', 'white vinegar', 'parsley', 'parsley', 'parsley', 'yellow onion']), + ('Roast Leg of Lamb with Crispy Moroccan Carrots & Couscous', ['oranges', 'rosemary', 'garlic', 'anchovy fillets', 'couscous', 'carrot', 'sesame seeds', 'fresh thyme', 'vinegar', 'olive oil', 'tahini', 'harissa', 'onions', 'honey', 'fresh mint', 'leg of lamb', 'tomatoes', 'baby carrot', 'vegetable bullion', 'filo pastry', 'celery', 'bay leaves', 'yoghurt', 'oranges', 'rosemary', 'rosemary', 'garlic', 'anchovy fillets', 'anchovy fillets', 'anchovy fillets']), + ('Baked Chicken Jollof Rice', ['tomato puree', 'garlic', 'ginger', 'tomato', 'carrot', 'thyme', 'white pepper', 'water', 'maggi cubes', 'chicken', 'rice', 'coriander', 'scotch bonnet pepper', 'bell pepper', 'onion', 'turmeric', 'salt', 'tomato puree', 'tomato puree', 'garlic', 'garlic', 'garlic', 'ginger']), + ('Seafood Risotto', ['garlic', 'tomato paste', 'baby scallops', 'mussels', 'water', 'crab legs', 'olive oil', 'baby squid', 'fish stock', 'lemon juice', 'white onion', 'arborio risotto rice', 'clams', 'parmesan cheese', 'flat-leaf parsley', 'cherry tomatoes', 'prawns', 'white wine']), + ('Lamb over Marinated Summer Squash with Hazelnuts and Ricotta', ['toasted bread', 'rosemary', 'hazelnuts', 'anchovy fillets', 'garlic', 'carrot', 'summer squash', 'black pepper', 'red pepper flakes', 'vinegar', 'sea salt', 'zucchini', 'olive oil', 'onions', 'white wine vinegar', 'fresh mint', 'leg of lamb', 'lemon', 'fresh ricotta', 'sugar', 'celery', 'bay leaves', 'kosher salt', 'toasted bread', 'toasted bread', 'rosemary', 'rosemary', 'rosemary', 'hazelnuts', 'anchovy fillets', 'garlic', 'garlic', 'carrot', 'summer squash', 'summer squash', 'summer squash']) + ] + +recipes_without_duplicates = [('kisir_with_warm_pita', 'Kisir with Warm Pita', {'water', 'chopped parsley', 'pomegranate molasses', 'spring onion', 'lemon juice', 'olive oil', 'bulgur', 'tomato paste', 'tomato', 'persian cucumber'}), + ('shakshuka', 'Shakshuka', {'smoked paprika', 'tomatoes', 'cumin', 'firm tofu', 'olive oil', 'harissa', 'yellow onion', 'sugar', "za'atar", 'tomato paste', 'cloves', 'red bell pepper', 'vegan unsweetened yoghurt'}), + ('vegetarian_khoresh_bademjan', 'Vegetarian Khoresh Bademjan', {'pomegranate concentrate', 'saffron powder', 'cayenne pepper', 'barberries', 'salt', 'yellow onions', 'yellow split peas', 'slivered almonds', 'ground turmeric', 'orange zest', 'lemon juice', 'kosher salt', 'hot water', 'basmati rice', 'black pepper', 'orange juice', 'tomato paste', 'vegan butter', 'chinese eggplants'}), + ('baked_kelewele', 'Baked Kelewele', {'salt', 'coconut oil', 'smoked paprika', 'cayenne pepper', 'red onion', 'fresh ginger', 'calabash nutmeg', 'grains of selim', 'black peppercorn', 'cloves', 'ripe plantains'}), + ('waakye', 'Waakye', {'salt', 'coconut oil', 'water', 'white rice', 'sorghum stems', 'black-eyed peas', 'baking soda'}), + ('georgian_eggplant_rolls_with_walnuts', 'Georgian Eggplant Rolls with Walnuts', {'salt', 'coriander', 'pomegranate seeds', 'oil', 'water', 'vinegar', 'garlic', 'eggplants', 'black pepper', 'khmeli suneli', 'walnuts'}), + ('burmese_tofu_with_garlic,_ginger_and_chili_sauce', 'Burmese Tofu with Garlic, Ginger and Chili Sauce', {'salt', 'rice vinegar', 'oil', 'water', 'turmeric', 'chili flakes', 'spring onions', 'brown sugar', 'garlic', 'chickpea flour', 'ginger', 'soy sauce', 'peanuts'}), + ('celeriac_schnitzel', 'Celeriac Schnitzel', {'salt', 'parsley', 'water', 'sunflower oil', 'flour', 'breadcrumbs', 'lemon', 'celeriac', 'chickpea flour', 'soy sauce', 'black pepper'}), + ('sticky_lemon_tofu', 'Sticky Lemon Tofu', {'salt', 'water', 'tofu', 'cornstarch', 'vegetable stock', 'vegetable oil', 'lemon juice', 'garlic', 'black pepper', 'ginger', 'soy sauce', 'sugar', 'lemon zest'}), + ('vegan_carbonara', 'Vegan Carbonara', {'salt', 'turmeric', 'spaghetti', 'lemon juice', 'olive oil', 'garlic', 'black pepper', 'nutritional yeast', 'soy sauce', 'smoked tofu', 'silken tofu', 'mixed herbs'}), + ('vegan_pizza_with_caramelized_onions', 'Vegan Pizza with Caramelized Onions', {'red pepper flakes', 'garlic', 'cashews', 'fresh basil', 'flour', 'tomatoes', 'red onion', 'oregano', 'nutritional yeast', 'rosemary', 'water', 'bell pepper', 'honey', 'barley malt', 'olive oil', 'salt', 'garlic powder', 'mushrooms', 'yeast', 'sugar'}), + ('cheela_with_spicy_mango_chutney', 'Cheela with Spicy Mango Chutney', {'hing', 'curry leaves', 'mangoes', 'garlic', 'nigella seeds', 'garlic paste', 'coriander seeds', 'oil', 'turmeric', 'red chili powder', 'coriander powder', 'cardamom powder', 'turmeric powder', 'clove powder', 'water', 'cumin powder', 'fresh ginger', 'vinegar', 'cinnamon powder', 'cilantro', 'chickpea flour', 'onion', 'salt', 'mango powder', 'fresh red chili', 'mashed potatoes', 'mustard seeds', 'serrano chili', 'garam masala', 'sugar'}), + ('sweet_and_spicy_crispy_green_beans', 'Sweet and Spicy Crispy Green Beans', {'sesame oil', 'siracha', 'sunflower oil', 'pomegranate molasses', 'sesame seeds', 'green beans', 'carrot', 'scallions', 'garlic', 'ginger', 'soy sauce', 'tomato paste', 'bell pepper'}), + ('vegan_mini_savory_mince_pies', 'Vegan Mini Savory Mince Pies', {'apples', 'brandy', 'pecans', 'raisins', 'brown sugar', 'lemon zest', 'dried blueberries', 'vegetarian worcestershire sauce', 'orange zest', 'butternut squash', 'corn flour', 'rosemary', 'vegetable stock', 'carrot', 'figs', 'cinnamon powder', 'olive oil', 'orange juice', 'black pepper', 'onion', 'dried cherries', 'salt', 'dried cranberries', 'parev shortcrust pastry', 'mushrooms', 'allspice powder', 'lemon juice', 'ginger', 'currants'}), + ('roasted_corn_and_zucchini_salad', 'Roasted Corn and Zucchini Salad', {'zucchini', 'tomatoes', 'green onions', 'corn', 'lemon juice', 'olive oil', 'black pepper', 'lemon zest', 'dill'}), + ('golden_potato_salad', 'Golden Potato Salad', {'salt', 'yukon gold potato', 'turmeric', 'balsamic vinegar', 'cumin seeds', 'lemon juice', 'olive oil', 'garlic', 'mustard seeds', 'black pepper', 'chives'}), + ('carrot_puff_pastry_tart', 'Carrot Puff Pastry Tart', {'salt', 'water', 'lemon', 'thyme', 'red onion', 'carrot', 'lemon juice', 'pareve puff pastry', 'ground almonds', 'brown sugar', 'olive oil', 'garlic', 'black pepper', 'vegan butter'}), + + ('mushroom_lasagna', 'Mushroom Lasagna', {'dried lasagna noodles', 'portobello mushrooms', 'nutmeg', 'flour', 'kosher salt', 'milk', 'olive oil', 'garlic', 'onions', 'butter', 'black pepper', 'parmesan cheese'}), + ('nut_wellington', 'Nut Wellington', {'apples', 'eggs', 'hazelnuts', 'pecans', 'thyme', 'dates', 'cashews', 'breadcrumbs', 'almonds', 'marmite', 'sage', 'leeks', 'olive oil', 'black pepper', 'walnuts', 'salt', 'chestnuts', 'brazil nuts', 'butter', 'puff pastry sheets'}), + ('white_cheddar_scalloped_potatoes', 'White Cheddar Scalloped Potatoes', {'yukon gold potato', 'shallots', 'cream', 'thyme', 'breadcrumbs', 'sharp white cheddar', 'kosher salt', 'milk', 'garlic'}), + ('winter_cobb_salad', 'Winter Cobb Salad', {'lacinato kale', 'eggs', 'red wine vinegar', 'shiitake mushrooms', 'tomatoes', 'avocados', 'olive oil', 'blue cheese', 'garlic', 'black pepper', 'onion', 'smoked tofu'}), + ('roast_pumpkin_and_lentil_salad_with_roasted_lemon_dressing', 'Roast Pumpkin and Lentil Salad with Roasted Lemon Dressing', {'red wine vinegar', 'dijon mustard', 'lemon', 'honey', 'red onion', 'feta cheese', 'olive oil', 'capers', 'pepitas', 'fresh pumpkin', 'watercress', 'green lentils', 'currants'}), + ('cambodian-style_vegetable_spring_rolls', 'Cambodian-Style Vegetable Spring Rolls', {'sunflower oil', 'vegetarian fish sauce', 'shallots', 'vermicelli noodles', 'wombok', 'firm tofu', 'lime juice', 'corn flour', 'palm sugar', 'bean sprouts', 'spring roll wrappers', 'garlic', 'red chili', 'soy sauce', 'toasted peanuts', 'carrot'}), + ('summer_minestrone_cups', 'Summer Minestrone Cups', {'leek', 'garlic', 'lemon zest', 'tomatoes', 'red chili', 'chickpeas', 'rosemary', 'carrot', 'vegetable bullion', 'fresh corn', 'fresh peas', 'green beans', 'olive oil', 'parmesan cheese', 'croutons', 'celery', 'mint', 'basil', 'green lentils', 'parmesan rind'}), + ('fried_zucchini_with_balsamic_and_chili_dressing', 'Fried Zucchini with Balsamic and Chili Dressing', {'zucchini', 'balsamic vinegar', 'honey', 'red onion', 'lemon juice', 'olive oil', 'mint leaves', 'garlic', 'red thai chili', 'pomegranate'}), + ('barley_risotto', 'Barley Risotto', {'beets', 'white wine', 'thyme', 'red onion', 'carrot', 'butternut squash', 'olive oil', 'sage', 'garlic', 'brussel sprouts', 'rosemary', 'black pepper', 'parmesan cheese', 'pearl barley', 'vegetable bullion'}), + ('cherry_tomato,_watercress_and_fava_bean_salad', 'Cherry Tomato, Watercress and Fava Bean Salad', {'salt', 'fresh or frozen fava beans', 'fresh peas', 'balsamic vinegar', 'olive oil', 'garlic', 'watercress', 'fresh cherry bocconcini', 'fresh cherry tomatoes'}), + ('fresh_garden_peas_over_cauliflower_almond_puree', 'Fresh Garden Peas over Cauliflower Almond Puree', {'grated nutmeg', 'red onions', 'lemon', 'fresh peas', 'cream', 'vegetable oil', 'olive oil', 'garlic', 'blanched almonds', 'cauliflower', 'fresh pea tendrils'}), + ('walnut_ravioli_with_artichokes_and_tomatoes', 'Walnut Ravioli with Artichokes and Tomatoes', {'salt', 'fresh tomatoes', 'ricotta cheese', 'lemon zest', 'olives', 'red onion', 'lemon juice', 'black pepper', 'rosemary', 'butter', 'basil', 'fresh artichoke hearts', 'pasta sheets', 'pine nuts', 'walnuts', 'oil marinated artichokes'}), + ('asparagus_puffs', 'Asparagus Puffs', {'salt', 'asparagus', 'ricotta cheese', 'thyme', 'puff pastry', 'red onion', 'eggs', 'lemon juice', 'black pepper', 'parmesan cheese', 'chives'}), + ('grilled_tofu_tacos', 'Grilled Tofu Tacos', {'carrot', 'red cabbage', 'ancho chili', 'limes', 'hot water', 'garlic', 'roasted corn', 'masa', 'pasilla chili', 'lemon', 'tomatoes', 'cumin', 'fresh cilantro leaves', 'chipotle chili', 'red onions', 'pepitas', 'tomatillos', 'black beans', 'cotija cheese', 'crema', 'firm tofu', 'lemon juice', 'jalapeño chili', 'avocado'}), + + ('zucchini_fritters_with_lemon-thyme_coconut_yogurt', 'Zucchini Fritters with Lemon-Thyme Coconut Yogurt', {'salt', 'coconut oil', 'eggs', 'fresh thai chili', 'coconut yogurt', 'zucchini', 'lemon juice', 'black pepper', 'coconut flour', 'chives', 'lemon zest', 'baking soda'}), + ('avocado_deviled_eggs', 'Avocado Deviled Eggs', {'salt', 'eggs', 'garlic powder', 'seranno chili', 'avocado', 'lime juice', 'pepitas', 'fresh cilantro leaves'}), + ('grilled_flank_steak_with_caesar_salad', 'Grilled Flank Steak with Caesar Salad', {'flank steak', 'avocado oil', 'treviso', 'scallions', 'garlic', 'cherry tomatoes', 'pine nuts', 'white vinegar', 'chipotle chili', 'dijon mustard', 'olive oil', 'avocado mayonnaise', 'black pepper', 'paleo parmesan cheese', 'castelfranco radicchio', 'fresh parsley', 'salt', 'worcestershire sauce', 'radishes'}), + ('pumpkin_bread_crostini', 'Pumpkin Bread Crostini', {'eggs', 'nutmeg', 'cinnamon', 'garlic', 'pumpkin puree', 'apple cider vinegar', 'cherry tomatoes', 'onions', 'coconut flour', 'cloves', 'shrimp', 'coconut oil', 'honey', 'olive oil', 'black pepper', 'almond butter', 'salt', 'fresh red chili', 'basil', 'baking soda'}), + ('blt_bites', 'BLT Bites', {'paleo mayonnaise', 'bacon', 'kale', 'cherry tomatoes', 'mustard seed', 'onion'}), + ('roasted_chicken_with_roasted_tomatoes,_avocado,_and_sweet_potatoes', 'Roasted Chicken with Roasted Tomatoes, Avocado, and Sweet Potatoes', {'safflower oil', 'shallots', 'whole chicken', 'lemons', 'tomatoes', 'purple sweet potato', 'avocados', 'limes', 'kosher salt', 'olive oil', 'mexican oregano', 'garlic', 'black pepper', 'cumin', 'chiles de árbol'}), + ('chicken_with_tamarind_and_apricot_sauce', 'Chicken with Tamarind and Apricot Sauce', {'cinnamon', 'garlic', 'cider vinegar', 'chipotles', 'homemade tamarind concentrate', 'roma tomatoes', 'white chicken', 'ground cumin', 'water', 'safflower oil', 'allspice', 'dried apricots', 'honey', 'olive oil', 'black pepper', 'salt', 'homemade apricot honey preserves', 'kosher salt', 'chili powder'}), + ('grilled_fish_tacos_with_cauliflower_tortillas', 'Grilled Fish Tacos with Cauliflower Tortillas', {'salt', 'eggs', 'smoked paprika', 'shredded red cabbage', 'mango', 'green onions', 'lime', 'cumin', 'tilapia', 'cilantro', 'black pepper', 'serrano chili', 'cauliflower', 'avocado'}), + ('grilled_pork_chops_with_mango_pineapple_salsa', 'Grilled Pork Chops with Mango Pineapple Salsa', {'pork chops', 'lacinato kale', 'chipotle chili', 'serrano chili', 'lime zest', 'pineapple', 'lime', 'garlic', 'onions', 'mangoes', 'cauliflower', 'avocado', 'cilantro leaves'}), + ('grilled_shrimp_and_pesto_over_zucchini_noodles', 'Grilled Shrimp and Pesto over Zucchini Noodles', {'salt', 'green bell pepper', 'cashews', 'zucchini', 'tomatoes', 'red bell pepper', 'cumin', 'lemon juice', 'yellow bell pepper', 'olive oil', 'garlic', 'pine nuts', 'basil', 'lemon zest', 'shrimp'}), + + ('cauliflower_pizza_with_roasted_tomatoes_and_chicken', 'Cauliflower Pizza with Roasted Tomatoes and Chicken', {'roasted chicken', 'eggs', 'fresh basil', 'olive oil', 'almond meal', 'cherry tomatoes', 'rosemary', 'cauliflower', 'mozzarella cheese', 'tomato paste', 'parmesan'}), + ('flank_steak_with_chimichurri_and_asparagus', 'Flank Steak with Chimichurri and Asparagus', {'fresh parsley', 'salt', 'asparagus', 'chipotle chili', 'flank steak', 'scallions', 'olive oil', 'garlic', 'black pepper', 'cauliflower', 'white vinegar', 'sour cream'}), + ('kingfish_lettuce_cups', 'Kingfish Lettuce Cups', {'oyster sauce', 'fish sauce', 'spring onions', 'sesame seeds', 'grilled king fish', 'little gem lettuce heads', 'mirin', 'red cabbage', 'lime juice', 'peanut oil', 'garlic', 'watermelon radishes', 'soy sauce', 'avocado'}), + ('butter_chicken_with_grilled_mushrooms,_brussel_sprouts_and_mango_chutney', 'Butter Chicken with Grilled Mushrooms, Brussel Sprouts and Mango Chutney', {'hing', 'curry leaves', 'cashew nuts', 'green chili', 'cinnamon', 'mangoes', 'garlic', 'nigella seeds', 'garlic paste', 'coriander seeds', 'turmeric', 'ginger garlic paste', 'tomatoes', 'red chili powder', 'coriander powder', 'cardamom powder', 'turmeric powder', 'clove powder', 'cloves', 'heavy cream', 'cardamom', 'fresh greek yogurt', 'monk fruit', 'fresh ginger', 'cumin powder', 'vinegar', 'cinnamon powder', 'cilantro', 'brussel sprouts', 'whole small crimini mushrooms', 'salt', 'boned chicken', 'red chili flakes', 'mango powder', 'fresh red chili', 'lemon juice', 'garam masala', 'butter', 'ginger', 'mustard seeds', 'chicken', 'dried fenugreek leaves'}), + ('prawn_and_herb_omelette', 'Prawn and Herb Omelette', {'salt', 'parsley', 'eggs', 'fresh cucumber', 'sesame seeds', 'green onions', 'monk fruit', 'lemon juice', 'olive oil', 'tahini', 'harissa', 'black pepper', 'butter', 'onion', 'fennel bulb', 'chives', 'shrimp', 'dill'}), + ('satay_steak_skewers', 'Satay Steak Skewers', {'flank steak', 'red and green thai chili', 'kecap manis', 'fish sauce', 'monk fruit', 'micro cilantro', 'carrot', 'apple cider vinegar', 'sriacha', 'lime juice', 'olive oil', 'cucumbers', 'roasted peanuts', 'crunchy peanut butter', 'peanuts'}), + ('parmesan_crackers_and_spinach_crackers_with_salmon_pate', 'Parmesan Crackers and Spinach Crackers with Salmon Pate', {'fresh cucumber', 'pecans', 'ghee', 'garlic', 'chives', 'flaxmeal', 'chili flakes', 'almond flour', 'salmon fillets', 'red onion', 'cherry tomatoes', 'coconut flour', 'cumin', 'spinach', 'cream cheese', 'avocado mayonnaise', 'black pepper', 'parmesan cheese', 'salt', 'lemon juice'}), + ('pork_chops_with_grilled_castelfranco_radicchio_and_asparagus', 'Pork Chops with Grilled Castelfranco Radicchio and Asparagus', {'pork chops', 'salt', 'asparagus', 'eggs', 'dijon mustard', 'avocado oil', 'lemon', 'thyme', 'monk fruit', 'oregano', 'avocado mayonnaise', 'garlic', 'black pepper', 'rosemary', 'butter', 'basil', 'castelfranco radicchio', 'dill'}), + ('seared_salmon_with_pickled_vegetable_and_watercress_salad', 'Seared Salmon with Pickled Vegetable and Watercress Salad', {'red wine vinegar', 'caster sugar', 'salmon steaks', 'radishes', 'shallots', 'red onion', 'pink peppercorns', 'toasted buckwheat', 'lemon juice', 'lime juice', 'red cabbage', 'watercress', 'fennel seeds', 'dutch carrot'}), + ('braised_pork_belly_with_apple_salad', 'Braised Pork Belly with Apple Salad', {'spring onions', 'dark soy sauce', 'light soy sauce', 'pork belly', 'monk fruit', 'green cabbage', 'star anise', 'sesame seeds', 'lemon juice', 'olive oil', 'black pepper', 'ginger', 'cinnamon sticks', 'granny smith apples', 'cilantro leaves'}), + + ('beachside_snapper', 'Beachside Snapper', {'yellow mustard', 'mayonnaise', 'limes', 'white onion', 'red snapper', 'fresh corn tortillas', 'tomatoes', 'red onion', 'lime juice', 'soy sauce', 'mexican crema', 'salsa', 'garlic cloves', 'green bell pepper', 'olive oil', 'black pepper', 'salt', 'yellow bell pepper', 'worcestershire sauce', 'anaheim chili', 'butter', 'red bell pepper'}), + ('governor_shrimp_tacos', 'Governor Shrimp Tacos', {'chile manzano', 'worcestershire sauce', 'oaxaca cheese', 'garlic cloves', 'red onion', 'avocado', 'lime juice', 'kosher salt', 'white onion', 'chipotle adobo sauce', 'poblano chili', 'fresh corn tortillas', 'butter', 'black pepper', 'pepitas', 'tomato paste', 'roma tomatoes', 'shelled large shrimp'}), + ('shrimp,_bacon_and_crispy_chickpea_tacos_with_salsa_de_guacamole', 'Shrimp, Bacon and Crispy Chickpea Tacos with Salsa de Guacamole', {'fresh tortillas', 'slivered almonds', 'bacon', 'sea salt', 'chickpeas', 'olive oil', 'guajillo chile', 'garlic', 'butter', 'black pepper', 'onion', 'shrimp', 'avocado'}), + ('burnt_masala_wings_with_classic_coleslaw', 'Burnt Masala Wings with Classic Coleslaw', {'mayonnaise', 'carrot', 'red cabbage', 'green cabbage', 'apple cider vinegar', 'lime juice', 'cloves', 'cinnamon sticks', 'sriracha', 'celery seeds', 'chicken wings', 'garlic cloves', 'honey', 'olive oil', 'cilantro', 'black pepper', 'chiles de árbol', 'tamarind concentrate', 'green cardamom', 'black cardamom', 'lemon juice', 'kosher salt', 'serrano chili', 'ginger', 'black peppercorns', 'butter'}), + ('dahi_puri_with_black_chickpeas', 'Dahi Puri with Black Chickpeas', {'roasted chicken', 'scallion chutney', 'yukon gold potato', 'turmeric', 'black chickpeas', 'whole-milk yogurt', 'chili powder', 'red onion', 'pani puri', 'ginger', 'mint', 'thin sev', 'date syrup', 'cumin', 'chaat masala', 'tamarind concentrate'}), + ('brisket_with_grilled_rhubarb,_onions,_and_fennel', 'Brisket with Grilled Rhubarb, Onions, and Fennel', {'crushed red pepper flakes', 'rhubarb', 'thyme', 'yellow onion', 'garlic', 'brown sugar', 'beer', 'lemon', 'red onion', 'oregano', 'soy sauce', 'white vinegar', 'beef brisket', 'parsley', 'marjoram', 'balsamic vinegar', 'vegetable oil', 'fennel bulbs', 'cilantro', 'black pepper', 'worcestershire sauce', 'celery', 'kosher salt', 'mint', 'chili powder'}), + ('roast_leg_of_lamb_with_crispy_moroccan_carrots_&_couscous', 'Roast Leg of Lamb with Crispy Moroccan Carrots & Couscous', {'bay leaves', 'fresh thyme', 'carrot', 'tahini', 'garlic', 'baby carrot', 'oranges', 'filo pastry', 'tomatoes', 'harissa', 'onions', 'rosemary', 'leg of lamb', 'vegetable bullion', 'sesame seeds', 'honey', 'anchovy fillets', 'vinegar', 'olive oil', 'couscous', 'fresh mint', 'celery', 'yoghurt'}), + ('baked_chicken_jollof_rice', 'Baked Chicken Jollof Rice', {'coriander', 'salt', 'white pepper', 'water', 'bell pepper', 'turmeric', 'rice', 'scotch bonnet pepper', 'chicken', 'thyme', 'maggi cubes', 'garlic', 'ginger', 'onion', 'tomato', 'carrot', 'tomato puree'}), + ('seafood_risotto', 'Seafood Risotto', {'white wine', 'water', 'clams', 'crab legs', 'baby squid', 'lemon juice', 'parmesan cheese', 'olive oil', 'white onion', 'garlic', 'arborio risotto rice', 'fish stock', 'mussels', 'flat-leaf parsley', 'tomato paste', 'prawns', 'baby scallops', 'cherry tomatoes'}), + ('lamb_over_marinated_summer_squash_with_hazelnuts_and_ricotta', 'Lamb over Marinated Summer Squash with Hazelnuts and Ricotta', {'red pepper flakes', 'hazelnuts', 'zucchini', 'bay leaves', 'carrot', 'garlic', 'white wine vinegar', 'toasted bread', 'lemon', 'onions', 'rosemary', 'leg of lamb', 'summer squash', 'sea salt', 'anchovy fillets', 'vinegar', 'olive oil', 'black pepper', 'fresh mint', 'celery', 'kosher salt', 'fresh ricotta', 'sugar'}) + ] + +############################## +# Data for test_check_drinks # +############################## + + +all_drinks = [('Amaretto Sour', ['almond liqueur', 'bourbon', 'cherries', 'egg white', 'lemon juice', 'lemon twist', 'simple syrup']), + ('Aperol Spritz', ['aperol', 'prosecco', 'soda water']), + ('Bannana Punch', ['banana', 'ginger ale', 'lemonade', 'orange juice', 'pineapple juice', 'sugar', 'water']), + ('Beet Sumac Soda', ['beet', 'club soda', 'fresh lemon juice', 'sugar', 'sumac']), + ('Better Than Celery Juice', ['apple cider vinegar', 'black pepper', 'celery stalks', 'club soda', 'granny smith apples', 'kosher salt', 'parsley']), + ('Black & Blue Berries', ['blackberries', 'blueberries', 'honey', 'lemon juice', 'soda water']), + ('Bloody Mary', ['celery', 'celery salt', 'lemon juice', 'pepper', 'tomato juice', 'vodka', 'worcestershire sauce']), + ('Bloody Shame', ['V8 juice', 'black pepper', 'celery', 'salt', 'tabasco sauce']), + ('Chai Blossom', ['chai tea bags', 'club soda', 'fresh lime juice', 'lemon twists', 'start anise pods', 'sugar']), + ('Chile-lime Pineapple Soda', ['chiles de árbol', 'club soda', 'fresh pineapple juice', 'kosher salt', 'lime juice', 'lime wedges', 'pink peppercorns', 'sugar']), + ('Citrus Fizz', ['organic marmalade cordial', 'seedlip grove 42', 'sparkling water']), + ('Dry Martini', ['dry vermouth', 'gin', 'lemon twist', 'olives']), + ('Espresso Martini', ['coffee liqueur', 'espresso', 'sugar syrup', 'vodka']), + ('Fermented Grape Soda', ['red seedless grapes', 'sugar', 'washed organic ginger']), + ('French 75', ['champagne', 'gin', 'lemon juice', 'sugar syrup']), + ('Gimlet', ['gin', 'lime juice', 'sugar syrup']), + ('Gin Fizz', ['gin', 'lemon juice', 'soda water', 'sugar syrup']), + ('Huckleberry Shrub', ['club soda', 'huckleberries', 'sugar', 'white wine vinegar']), + ('Mai Tai', ['cherries', 'lime juice', 'lime wedge', 'mint leaves', 'orange curacao', 'orgeat syrup', 'rum', 'sugar syrup']), + ('Mango Mule', ['cucumber', 'fresh lime juice', 'ginger beer', 'honey syrup', 'ice', 'mango puree']), + ('Manhattan', ['bitters', 'cherry', 'rye', 'sweet vermouth']), + ('Maple-Ginger Cider Switchel', ['apple cider vinegar', 'club soda', 'fresh ginger', 'fresh lime juice', 'maple syrup', 'mint sprigs']), + ('Margarita', ['lime juice', 'salt', 'simple syrup', 'tequila', 'triple sec']), + ('Mojito', ['lime', 'mint leaves', 'soda water', 'sugar syrup', 'white rum']), + ('Moscow Mule', ['ginger beer', 'lime', 'lime juice', 'vodka']), + ('Negroni', ['bitters', 'gin', 'sweet vermouth']), + ('Old Fashioned', ['bitters', 'bourbon', 'orange juice', 'orange slices', 'sugar']), + ('PG13 Singapore Sling', ['fresh lime juice', 'mango juice', 'mint sprigs', 'pineapple juice', 'pomegranate juice', 'tonic water']), + ('Penicillin', ['ginger', 'honey simple syrup', 'lemon juice', 'scotch']), + ('Pina Colada', ['cherries', 'coconut milk', 'cream of coconut', 'dark rum', 'fresh pineapple', 'lime juice', 'white rum']), + ('Raspberry Almond Soda', ['almonds', 'club soda', 'kosher salt', 'limes', 'ripe raspberries', 'sugar']), + ('Salted Meyer Lemon and Sage Presse', ['club soda meyer lemons', 'kosher salt', 'sage leaves', 'simple syrup']), + ('Salted Watermelon Juice', ['cubed watermelon', 'kosher salt', 'lime wedges']), + ('Shirley Tonic', ['cinnamon sticks', 'club soda', 'ginger', 'lemon twists', 'pomegranate juice', 'sugar', 'whole cloves']), + ('Shirley ginger', ['brooklyn crafted lemon lime ginger beer', 'club soda', 'grenadine', 'lime juice']), + ('Spiced Hibiscus Tea', ['cinnamon sticks', 'dried hibiscus flowers', 'ginger', 'honey', 'lemon juice', 'lemon wheels', 'whole allspice']), + ('Turmeric Tonic', ['agave syrup', 'cayenne pepper', 'lemon', 'peeled ginger', 'peeled turmeric', 'sparkling water']), + ('Virgin Cucumber Gimlet', [';ime juice', 'club soda', 'muddled cucumber', 'simple syrup']), + ('Whiskey Sour', ['cherry', 'lemon juice', 'lemon slices', 'superfine sugar', 'whiskey']) + ] + +drink_names = ['Amaretto Sour Cocktail','Aperol Spritz Cocktail','Bannana Punch Mocktail','Beet Sumac Soda Mocktail', + 'Better Than Celery Juice Mocktail','Black & Blue Berries Mocktail','Bloody Mary Cocktail', + 'Bloody Shame Mocktail','Chai Blossom Mocktail','Chile-lime Pineapple Soda Mocktail', + 'Citrus Fizz Mocktail','Dry Martini Cocktail','Espresso Martini Cocktail','Fermented Grape Soda Mocktail', + 'French 75 Cocktail','Gimlet Cocktail','Gin Fizz Cocktail','Huckleberry Shrub Mocktail', + 'Mai Tai Cocktail','Mango Mule Mocktail','Manhattan Cocktail','Maple-Ginger Cider Switchel Mocktail', + 'Margarita Cocktail','Mojito Cocktail','Moscow Mule Cocktail','Negroni Cocktail', + 'Old Fashioned Cocktail','PG13 Singapore Sling Mocktail','Penicillin Cocktail','Pina Colada Cocktail', + 'Raspberry Almond Soda Mocktail','Salted Meyer Lemon and Sage Presse Mocktail', + 'Salted Watermelon Juice Mocktail','Shirley Tonic Mocktail','Shirley ginger Mocktail', + 'Spiced Hibiscus Tea Mocktail','Turmeric Tonic Mocktail','Virgin Cucumber Gimlet Mocktail', + 'Whiskey Sour Cocktail'] + + +################################# +# Data for test_categorize_dish # +################################# + +all_dishes = recipes_without_duplicates + +dishes_categorized = ['Zucchini Fritters with Lemon-Thyme Coconut Yogurt: PALEO', + 'Winter Cobb Salad: VEGETARIAN', + 'White Cheddar Scalloped Potatoes: VEGETARIAN', + 'Walnut Ravioli with Artichokes and Tomatoes: VEGETARIAN', + 'Waakye: VEGAN', + 'Vegetarian Khoresh Bademjan: VEGAN', + 'Vegan Pizza with Caramelized Onions: VEGAN', + 'Vegan Mini Savory Mince Pies: VEGAN', + 'Vegan Carbonara: VEGAN', + 'Sweet and Spicy Crispy Green Beans: VEGAN', + 'Summer Minestrone Cups: VEGETARIAN', + 'Sticky Lemon Tofu: VEGAN', + 'Shrimp, Bacon and Crispy Chickpea Tacos with Salsa de Guacamole: OMNIVORE', + 'Shakshuka: VEGAN', + 'Seared Salmon with Pickled Vegetable and Watercress Salad: KETO', + 'Seafood Risotto: OMNIVORE', + 'Satay Steak Skewers: KETO', + 'Roasted Corn and Zucchini Salad: VEGAN', + 'Roasted Chicken with Roasted Tomatoes, Avocado, and Sweet Potatoes: PALEO', + 'Roast Pumpkin and Lentil Salad with Roasted Lemon Dressing: VEGETARIAN', + 'Roast Leg of Lamb with Crispy Moroccan Carrots & Couscous: OMNIVORE', + 'Pumpkin Bread Crostini: PALEO', + 'Prawn and Herb Omelette: KETO', + 'Pork Chops with Grilled Castelfranco Radicchio and Asparagus: KETO', + 'Parmesan Crackers and Spinach Crackers with Salmon Pate: KETO', + 'Nut Wellington: VEGETARIAN', + 'Mushroom Lasagna: VEGETARIAN', + 'Lamb over Marinated Summer Squash with Hazelnuts and Ricotta: OMNIVORE', + 'Kisir with Warm Pita: VEGAN', + 'Kingfish Lettuce Cups: KETO', + 'Grilled Tofu Tacos: VEGETARIAN', + 'Grilled Shrimp and Pesto over Zucchini Noodles: PALEO', + 'Grilled Pork Chops with Mango Pineapple Salsa: PALEO', + 'Grilled Flank Steak with Caesar Salad: PALEO', + 'Grilled Fish Tacos with Cauliflower Tortillas: PALEO', + 'Governor Shrimp Tacos: OMNIVORE', + 'Golden Potato Salad: VEGAN', + 'Georgian Eggplant Rolls with Walnuts: VEGAN', + 'Fried Zucchini with Balsamic and Chili Dressing: VEGETARIAN', + 'Fresh Garden Peas over Cauliflower Almond Puree: VEGETARIAN', + 'Flank Steak with Chimichurri and Asparagus: KETO', + 'Dahi Puri with Black Chickpeas: OMNIVORE', + 'Chicken with Tamarind and Apricot Sauce: PALEO', + 'Cherry Tomato, Watercress and Fava Bean Salad: VEGETARIAN', + 'Cheela with Spicy Mango Chutney: VEGAN', + 'Celeriac Schnitzel: VEGAN', + 'Cauliflower Pizza with Roasted Tomatoes and Chicken: KETO', + 'Carrot Puff Pastry Tart: VEGAN', + 'Cambodian-Style Vegetable Spring Rolls: VEGETARIAN', + 'Butter Chicken with Grilled Mushrooms, Brussel Sprouts and Mango Chutney: KETO', + 'Burnt Masala Wings with Classic Coleslaw: OMNIVORE', + 'Burmese Tofu with Garlic, Ginger and Chili Sauce: VEGAN', + 'Brisket with Grilled Rhubarb, Onions, and Fennel: OMNIVORE', + 'Braised Pork Belly with Apple Salad: KETO', + 'BLT Bites: PALEO', + 'Beachside Snapper: OMNIVORE', + 'Barley Risotto: VEGETARIAN', + 'Baked Kelewele: VEGAN', + 'Baked Chicken Jollof Rice: OMNIVORE', + 'Avocado Deviled Eggs: PALEO', + 'Asparagus Puffs: VEGETARIAN'] + + +######################################### +# Data for test_tag_special_ingredients # +######################################### + + +dupes = ['Baked Kelewele', 'Barley Risotto', 'Burmese Tofu with Garlic, Ginger and Chili Sauce', + 'Cambodian-Style Vegetable Spring Rolls', 'Fried Zucchini with Balsamic and Chili Dressing', + 'Kisir with Warm Pita', 'Shakshuka', 'Summer Minestrone Cups', 'Vegetarian Khoresh Bademjan'] + +nondupes = ['Brisket with Grilled Rhubarb, Onions, and Fennel', 'Burnt Masala Wings with Classic Coleslaw', + 'Butter Chicken with Grilled Mushrooms, Brussel Sprouts and Mango Chutney', + 'Cauliflower Pizza with Roasted Tomatoes and Chicken', 'Dahi Puri with Black Chickpeas', + 'Flank Steak with Chimichurri and Asparagus', 'Kingfish Lettuce Cups', + 'Shrimp, Bacon and Crispy Chickpea Tacos with Salsa de Guacamole'] + +group_1 = [item for item in recipes_with_duplicates if item[0] in dupes] +group_2 = [(item[1], item[2]) for item in recipes_without_duplicates if item[1] in nondupes] + +dishes_to_special_label = sorted(group_1 + group_2) + +dishes_labeled = [('Baked Kelewele', {'red onion'}), + ('Barley Risotto', {'garlic', 'red onion', 'parmesan cheese'}), + ('Brisket with Grilled Rhubarb, Onions, and Fennel', {'soy sauce', 'garlic', 'red onion', 'yellow onion'}), + ('Burmese Tofu with Garlic, Ginger and Chili Sauce', {'soy sauce', 'garlic', 'peanuts'}), + ('Burnt Masala Wings with Classic Coleslaw', {'honey', 'butter', 'garlic cloves'}), + ('Butter Chicken with Grilled Mushrooms, Brussel Sprouts and Mango Chutney', {'heavy cream', 'garlic', 'butter', 'tomatoes'}), + ('Cambodian-Style Vegetable Spring Rolls', {'soy sauce', 'firm tofu', 'garlic', 'toasted peanuts'}), + ('Cauliflower Pizza with Roasted Tomatoes and Chicken', {'parmesan', 'mozzarella cheese', 'tomato paste', 'cherry tomatoes', 'eggs'}), + ('Dahi Puri with Black Chickpeas', {'red onion', 'whole-milk yogurt'}), + ('Flank Steak with Chimichurri and Asparagus', {'garlic'}), + ('Fried Zucchini with Balsamic and Chili Dressing', {'honey', 'garlic', 'red onion'}), + ('Kingfish Lettuce Cups', {'soy sauce', 'oyster sauce', 'garlic', 'grilled king fish'}), + ('Kisir with Warm Pita', {'bulgur', 'tomato paste'}), + ('Shakshuka', {'tomatoes', 'tomato paste', 'firm tofu', 'yellow onion'}), + ('Shrimp, Bacon and Crispy Chickpea Tacos with Salsa de Guacamole', {'shrimp', 'garlic', 'butter', 'slivered almonds', 'bacon'}), + ('Summer Minestrone Cups', {'garlic', 'tomatoes', 'parmesan cheese'}), + ('Vegetarian Khoresh Bademjan', {'slivered almonds', 'tomato paste'})] + + +##################################### +# Data for test_compile_ingredients # +##################################### + + +ingredients_only = [[{'bulgur', 'pomegranate molasses', 'chopped parsley', 'lemon juice', 'tomato', 'persian cucumber', 'tomato paste', 'spring onion', 'water', 'olive oil'}, + {'vegan unsweetened yoghurt', 'yellow onion', 'firm tofu', 'smoked paprika', 'tomatoes', 'tomato paste', 'sugar', 'cloves', 'cumin', "za'atar", 'olive oil', 'harissa', 'red bell pepper'}, + {'yellow split peas', 'tomato paste', 'black pepper', 'pomegranate concentrate', 'yellow onions', 'slivered almonds', 'ground turmeric', 'barberries', 'basmati rice', 'lemon juice', 'hot water', 'cayenne pepper', 'chinese eggplants', 'salt', 'orange juice', 'saffron powder', 'vegan butter', 'orange zest', 'kosher salt'}, + {'smoked paprika', 'black peppercorn', 'red onion', 'grains of selim', 'cayenne pepper', 'calabash nutmeg', 'coconut oil', 'cloves', 'fresh ginger', 'salt', 'ripe plantains'}, + {'baking soda', 'sorghum stems', 'coconut oil', 'black-eyed peas', 'water', 'salt', 'white rice'}, + {'pomegranate seeds', 'oil', 'coriander', 'garlic', 'khmeli suneli', 'eggplants', 'black pepper', 'vinegar', 'walnuts', 'water', 'salt'}, + {'soy sauce', 'oil', 'chili flakes', 'garlic', 'brown sugar', 'ginger', 'peanuts', 'rice vinegar', 'spring onions', 'water', 'turmeric', 'salt', 'chickpea flour'}, + {'soy sauce', 'parsley', 'lemon', 'sunflower oil', 'black pepper', 'celeriac', 'breadcrumbs', 'water', 'salt', 'flour', 'chickpea flour'}, + {'soy sauce', 'vegetable stock', 'tofu', 'cornstarch', 'lemon juice', 'lemon zest', 'garlic', 'ginger', 'black pepper', 'sugar', 'water', 'salt', 'vegetable oil'}, + {'soy sauce', 'smoked tofu', 'lemon juice', 'nutritional yeast', 'mixed herbs', 'garlic', 'black pepper', 'silken tofu', 'turmeric', 'salt', 'olive oil', 'spaghetti'}, + {'mushrooms', 'rosemary', 'garlic', 'red pepper flakes', 'yeast', 'barley malt', 'water', 'olive oil', 'garlic powder', 'oregano', 'honey', 'nutritional yeast', 'red onion', 'tomatoes', 'cashews', 'sugar', 'bell pepper', 'flour', 'salt', 'fresh basil'}, + {'clove powder', 'oil', 'cinnamon powder', 'nigella seeds', 'curry leaves', 'coriander seeds', 'garlic', 'mangoes', 'mashed potatoes', 'cardamom powder', 'vinegar', 'water', 'mustard seeds', 'coriander powder', 'cumin powder', 'mango powder', 'garam masala', 'red chili powder', 'hing', 'garlic paste', 'turmeric powder', 'cilantro', 'sugar', 'onion', 'serrano chili', 'fresh ginger', 'turmeric', 'salt', 'fresh red chili', 'chickpea flour'}, + {'soy sauce', 'pomegranate molasses', 'sesame oil', 'green beans', 'sunflower oil', 'scallions', 'garlic', 'carrot', 'ginger', 'sesame seeds', 'tomato paste', 'bell pepper', 'siracha'}, + {'mushrooms', 'cinnamon powder', 'rosemary', 'corn flour', 'ginger', 'brown sugar', 'carrot', 'black pepper', 'raisins', 'butternut squash', 'vegetarian worcestershire sauce', 'parev shortcrust pastry', 'olive oil', 'vegetable stock', 'dried cherries', 'lemon juice', 'lemon zest', 'figs', 'dried cranberries', 'apples', 'pecans', 'onion', 'orange juice', 'currants', 'dried blueberries', 'salt', 'brandy', 'orange zest', 'allspice powder'}, + {'green onions', 'lemon juice', 'lemon zest', 'dill', 'corn', 'tomatoes', 'black pepper', 'zucchini', 'olive oil'}, + {'mustard seeds', 'cumin seeds', 'lemon juice', 'garlic', 'black pepper', 'balsamic vinegar', 'yukon gold potato', 'chives', 'turmeric', 'salt', 'olive oil'}, + {'olive oil', 'lemon', 'lemon juice', 'pareve puff pastry', 'brown sugar', 'red onion', 'carrot', 'garlic', 'black pepper', 'thyme', 'vegan butter', 'water', 'salt', 'ground almonds'} + ], + + [{'nutmeg', 'garlic', 'black pepper', 'onions', 'butter', 'parmesan cheese', 'portobello mushrooms', 'flour', 'dried lasagna noodles', 'olive oil', 'milk', 'kosher salt'}, + {'sage', 'puff pastry sheets', 'hazelnuts', 'almonds', 'black pepper', 'thyme', 'marmite', 'breadcrumbs', 'walnuts', 'dates', 'eggs', 'olive oil', 'brazil nuts', 'leeks', 'chestnuts', 'cashews', 'apples', 'pecans', 'butter', 'salt'}, + {'shallots', 'garlic', 'cream', 'thyme', 'breadcrumbs', 'sharp white cheddar', 'yukon gold potato', 'milk', 'kosher salt'}, + {'smoked tofu', 'shiitake mushrooms', 'red wine vinegar', 'garlic', 'tomatoes', 'black pepper', 'avocados', 'blue cheese', 'onion', 'lacinato kale', 'eggs', 'olive oil'}, + {'honey', 'lemon', 'dijon mustard', 'feta cheese', 'red wine vinegar', 'red onion', 'watercress', 'green lentils', 'currants', 'capers', 'pepitas', 'fresh pumpkin', 'olive oil'}, + {'lime juice', 'toasted peanuts', 'firm tofu', 'garlic', 'corn flour', 'bean sprouts', 'carrot', 'palm sugar', 'shallots', 'red chili', 'vermicelli noodles', 'wombok', 'soy sauce', 'sunflower oil', 'spring roll wrappers', 'vegetarian fish sauce'}, + {'fresh peas', 'rosemary', 'garlic', 'chickpeas', 'carrot', 'leek', 'green lentils', 'red chili', 'olive oil', 'croutons', 'fresh corn', 'lemon zest', 'green beans', 'parmesan rind', 'basil', 'tomatoes', 'vegetable bullion', 'parmesan cheese', 'celery', 'mint'}, + {'honey', 'lemon juice', 'garlic', 'red onion', 'red thai chili', 'pomegranate', 'balsamic vinegar', 'mint leaves', 'zucchini', 'olive oil'}, + {'sage', 'beets', 'pearl barley', 'brussel sprouts', 'rosemary', 'garlic', 'carrot', 'red onion', 'black pepper', 'thyme', 'butternut squash', 'vegetable bullion', 'parmesan cheese', 'olive oil', 'white wine'}, + {'fresh peas', 'fresh cherry tomatoes', 'garlic', 'watercress', 'balsamic vinegar', 'fresh or frozen fava beans', 'fresh cherry bocconcini', 'salt', 'olive oil'}, + {'red onions', 'lemon', 'fresh peas', 'garlic', 'grated nutmeg', 'cream', 'cauliflower', 'blanched almonds', 'fresh pea tendrils', 'olive oil', 'vegetable oil'}, + {'pine nuts', 'oil marinated artichokes', 'olives', 'rosemary', 'fresh tomatoes', 'ricotta cheese', 'black pepper', 'fresh artichoke hearts', 'walnuts', 'pasta sheets', 'lemon juice', 'lemon zest', 'basil', 'red onion', 'butter', 'salt'}, + {'egg', 'asparagus', 'lemon juice', 'red onion', 'ricotta cheese', 'black pepper', 'thyme', 'salt', 'parmesan cheese', 'puff pastry', 'chives'}, + {'cotija cheese', 'masa', 'fresh cilantro leaves', 'jalapeño chili', 'chipotle chili', 'firm tofu', 'garlic', 'carrot', 'roasted corn', 'tomatillos', 'pepitas', 'ancho chili', 'crema', 'red onions', 'pasilla chili', 'lemon', 'hot water', 'lemon juice', 'tomatoes', 'avocado', 'cumin', 'red cabbage', 'limes', 'black beans'} + ], + + [{'baking soda', 'coconut flour', 'lemon juice', 'lemon zest', 'eggs', 'coconut yogurt', 'black pepper', 'fresh thai chili', 'coconut oil', 'chives', 'zucchini', 'salt'}, + {'lime juice', 'fresh cilantro leaves', 'eggs', 'seranno chili', 'avocado', 'pepitas', 'salt', 'garlic powder'}, + {'pine nuts', 'white vinegar', 'chipotle chili', 'scallions', 'garlic', 'paleo parmesan cheese', 'black pepper', 'avocado oil', 'treviso', 'olive oil', 'radishes', 'flank steak', 'dijon mustard', 'castelfranco radicchio', 'worcestershire sauce', 'fresh parsley', 'cherry tomatoes', 'salt', 'avocado mayonnaise'}, + {'coconut flour', 'garlic', 'black pepper', 'cloves', 'eggs', 'olive oil', 'onions', 'honey', 'apple cider vinegar', 'almond butter', 'baking soda', 'nutmeg', 'pumpkin puree', 'cinnamon', 'shrimp', 'basil', 'coconut oil', 'cherry tomatoes', 'salt', 'fresh red chili'}, + {'mustard seed', 'onion', 'kale', 'cherry tomatoes', 'bacon', 'paleo mayonnaise'}, + {'purple sweet potato', 'chiles de árbol', 'garlic', 'tomatoes', 'safflower oil', 'black pepper', 'mexican oregano', 'avocados', 'shallots', 'cumin', 'olive oil', 'lemons', 'whole chicken', 'limes', 'kosher salt'}, + {'garlic', 'black pepper', 'dried apricots', 'roma tomatoes', 'water', 'olive oil', 'honey', 'cinnamon', 'ground cumin', 'cider vinegar', 'chili powder', 'safflower oil', 'homemade tamarind concentrate', 'white chicken', 'allspice', 'chipotles', 'salt', 'homemade apricot honey preserves', 'kosher salt'}, + {'green onions', 'serrano chili', 'shredded red cabbage', 'smoked paprika', 'mango', 'eggs', 'black pepper', 'cilantro', 'cauliflower', 'avocado', 'lime', 'cumin', 'salt', 'tilapia'}, + {'cilantro leaves', 'lime', 'pineapple', 'chipotle chili', 'garlic', 'mangoes', 'cauliflower', 'avocado', 'serrano chili', 'pork chops', 'lime zest', 'lacinato kale', 'onions'}, + {'pine nuts', 'shrimp', 'green bell pepper', 'lemon juice', 'basil', 'lemon zest', 'garlic', 'tomatoes', 'cashews', 'yellow bell pepper', 'cumin', 'zucchini', 'salt', 'olive oil', 'red bell pepper'} + ], + + [{'parmesan', 'almond meal', 'rosemary', 'mozzarella cheese', 'roasted chicken', 'tomato paste', 'cauliflower', 'cherry tomatoes', 'eggs', 'fresh basil', 'olive oil'}, + {'white vinegar', 'asparagus', 'flank steak', 'chipotle chili', 'scallions', 'garlic', 'black pepper', 'cauliflower', 'sour cream', 'fresh parsley', 'salt', 'olive oil'}, + {'soy sauce', 'watermelon radishes', 'lime juice', 'fish sauce', 'mirin', 'little gem lettuce heads', 'peanut oil', 'garlic', 'sesame seeds', 'oyster sauce', 'spring onions', 'avocado', 'grilled king fish', 'red cabbage'}, + {'clove powder', 'curry leaves', 'coriander seeds', 'ginger', 'cardamom powder', 'vinegar', 'mustard seeds', 'mango powder', 'garam masala', 'red chili powder', 'chicken', 'hing', 'turmeric powder', 'tomatoes', 'ginger garlic paste', 'fresh greek yogurt', 'fresh ginger', 'monk fruit', 'turmeric', 'cashew nuts', 'salt', 'fresh red chili', 'cinnamon powder', 'nigella seeds', 'whole small crimini mushrooms', 'brussel sprouts', 'garlic', 'mangoes', 'heavy cream', 'cloves', 'coriander powder', 'cumin powder', 'cardamom', 'green chili', 'cinnamon', 'garlic paste', 'red chili flakes', 'lemon juice', 'cilantro', 'butter', 'dried fenugreek leaves', 'boned chicken'}, + {'green onions', 'parsley', 'sesame seeds', 'black pepper', 'chives', 'eggs', 'fennel bulb', 'tahini', 'olive oil', 'harissa', 'shrimp', 'lemon juice', 'dill', 'butter', 'onion', 'fresh cucumber', 'monk fruit', 'salt'}, + {'sriacha', 'apple cider vinegar', 'lime juice', 'fish sauce', 'red and green thai chili', 'flank steak', 'carrot', 'peanuts', 'cucumbers', 'roasted peanuts', 'crunchy peanut butter', 'kecap manis', 'monk fruit', 'micro cilantro', 'olive oil'}, + {'spinach', 'parmesan cheese', 'coconut flour', 'chili flakes', 'garlic', 'black pepper', 'cream cheese', 'ghee', 'lemon juice', 'flaxmeal', 'red onion', 'salt', 'salmon fillets', 'pecans', 'almond flour', 'cumin', 'fresh cucumber', 'cherry tomatoes', 'chives', 'avocado mayonnaise'}, + {'rosemary', 'garlic', 'black pepper', 'thyme', 'avocado oil', 'eggs', 'oregano', 'asparagus', 'lemon', 'dijon mustard', 'basil', 'castelfranco radicchio', 'dill', 'butter', 'pork chops', 'monk fruit', 'salt', 'avocado mayonnaise'}, + {'lime juice', 'caster sugar', 'toasted buckwheat', 'lemon juice', 'red wine vinegar', 'red onion', 'dutch carrot', 'salmon steaks', 'watercress', 'pink peppercorns', 'shallots', 'fennel seeds', 'red cabbage', 'radishes'}, + {'cilantro leaves', 'green cabbage', 'lemon juice', 'pork belly', 'dark soy sauce', 'granny smith apples', 'ginger', 'light soy sauce', 'sesame seeds', 'black pepper', 'cinnamon sticks', 'spring onions', 'star anise', 'monk fruit', 'olive oil'} + ], + + [{'lime juice', 'salsa', 'green bell pepper', 'anaheim chili', 'black pepper', 'olive oil', 'yellow mustard', 'red bell pepper', 'soy sauce', 'mexican crema', 'mayonnaise', 'white onion', 'garlic cloves', 'fresh corn tortillas', 'red onion', 'tomatoes', 'limes', 'worcestershire sauce', 'butter', 'yellow bell pepper', 'salt', 'red snapper'}, + {'lime juice', 'poblano chili', 'tomato paste', 'black pepper', 'chipotle adobo sauce', 'chile manzano', 'roma tomatoes', 'pepitas', 'oaxaca cheese', 'white onion', 'shelled large shrimp', 'garlic cloves', 'fresh corn tortillas', 'red onion', 'worcestershire sauce', 'avocado', 'butter', 'kosher salt'}, + {'fresh tortillas', 'shrimp', 'garlic', 'chickpeas', 'black pepper', 'slivered almonds', 'guajillo chile', 'bacon', 'sea salt', 'butter', 'onion', 'avocado', 'olive oil'}, + {'lime juice', 'green cabbage', 'chiles de árbol', 'green cardamom', 'ginger', 'carrot', 'sriracha', 'black pepper', 'cinnamon sticks', 'celery seeds', 'cloves', 'black cardamom', 'olive oil', 'chicken wings', 'apple cider vinegar', 'mayonnaise', 'honey', 'black peppercorns', 'lemon juice', 'garlic cloves', 'tamarind concentrate', 'cilantro', 'butter', 'serrano chili', 'red cabbage', 'kosher salt'}, + {'whole-milk yogurt', 'chaat masala', 'ginger', 'pani puri', 'scallion chutney', 'yukon gold potato', 'black chickpeas', 'thin sev', 'date syrup', 'red onion', 'roasted chicken', 'chili powder', 'tamarind concentrate', 'cumin', 'turmeric', 'mint'}, + {'white vinegar', 'parsley', 'yellow onion', 'rhubarb', 'garlic', 'brown sugar', 'black pepper', 'thyme', 'crushed red pepper flakes', 'fennel bulbs', 'beer', 'marjoram', 'vegetable oil', 'soy sauce', 'oregano', 'lemon', 'red onion', 'chili powder', 'cilantro', 'beef brisket', 'balsamic vinegar', 'worcestershire sauce', 'celery', 'mint', 'kosher salt'}, + {'oranges', 'rosemary', 'garlic', 'anchovy fillets', 'couscous', 'carrot', 'sesame seeds', 'fresh thyme', 'vinegar', 'olive oil', 'tahini', 'harissa', 'onions', 'honey', 'fresh mint', 'leg of lamb', 'tomatoes', 'baby carrot', 'vegetable bullion', 'filo pastry', 'celery', 'bay leaves', 'yoghurt'}, + {'tomato puree', 'garlic', 'ginger', 'tomato', 'carrot', 'thyme', 'white pepper', 'water', 'maggi cubes', 'chicken', 'rice', 'coriander', 'scotch bonnet pepper', 'bell pepper', 'onion', 'turmeric', 'salt'}, + {'garlic', 'tomato paste', 'baby scallops', 'mussels', 'water', 'crab legs', 'olive oil', 'baby squid', 'fish stock', 'lemon juice', 'white onion', 'arborio risotto rice', 'clams', 'parmesan cheese', 'flat-leaf parsley', 'cherry tomatoes', 'prawns', 'white wine'}, + {'toasted bread', 'rosemary', 'hazelnuts', 'anchovy fillets', 'garlic', 'carrot', 'summer squash', 'black pepper', 'red pepper flakes', 'vinegar', 'sea salt', 'zucchini', 'olive oil', 'onions', 'white wine vinegar', 'fresh mint', 'leg of lamb', 'lemon', 'fresh ricotta', 'sugar', 'celery', 'bay leaves', 'kosher salt'} + ]] + + +##################################### +# Data for test_separate_appetizers # +##################################### + + +vegan = ['Kisir with Warm Pita', 'Shakshuka', 'Vegetarian Khoresh Bademjan', 'Baked Kelewele', 'Waakye', 'Georgian Eggplant Rolls with Walnuts', 'Burmese Tofu with Garlic, Ginger and Chili Sauce', 'Celeriac Schnitzel', 'Sticky Lemon Tofu', 'Vegan Carbonara', 'Vegan Pizza with Caramelized Onions', 'Cheela with Spicy Mango Chutney', 'Sweet and Spicy Crispy Green Beans', 'Vegan Mini Savory Mince Pies', 'Roasted Corn and Zucchini Salad', 'Golden Potato Salad', 'Carrot Puff Pastry Tart', 'Kisir with Warm Pita', 'Baked Kelewele', 'Burmese Tofu with Garlic, Ginger and Chili Sauce', 'Vegan Carbonara', 'Sweet and Spicy Crispy Green Beans', 'Golden Potato Salad'] +vegan_appetizers = ['Georgian Eggplant Rolls with Walnuts', 'Cheela with Spicy Mango Chutney', 'Vegan Mini Savory Mince Pies', 'Carrot Puff Pastry Tart', 'Georgian Eggplant Rolls with Walnuts', 'Carrot Puff Pastry Tart'] +vegan_dishes = ['Golden Potato Salad', 'Roasted Corn and Zucchini Salad', 'Sticky Lemon Tofu', 'Shakshuka', 'Burmese Tofu with Garlic, Ginger and Chili Sauce', 'Vegan Pizza with Caramelized Onions', 'Celeriac Schnitzel', 'Waakye', 'Vegan Carbonara', 'Sweet and Spicy Crispy Green Beans', 'Vegetarian Khoresh Bademjan', 'Baked Kelewele', 'Kisir with Warm Pita'] +vegan_appetizer_names = ['Georgian Eggplant Rolls with Walnuts','Cheela with Spicy Mango Chutney','Vegan Mini Savory Mince Pies','Carrot Puff Pastry Tart'] + + +vegetarian = ['Mushroom Lasagna', 'Nut Wellington', 'Roast Pumpkin and Lentil Salad with Roasted Lemon Dressing', 'Cambodian-Style Vegetable Spring Rolls', 'Summer Minestrone Cups', 'Fried Zucchini with Balsamic and Chili Dressing', 'Barley Risotto', 'Cherry Tomato, Watercress and Fava Bean Salad', 'Fresh Garden Peas over Cauliflower Almond Puree', 'Walnut Ravioli with Artichokes and Tomatoes', 'Asparagus Puffs', 'Grilled Tofu Tacos', 'Mushroom Lasagna', 'Cambodian-Style Vegetable Spring Rolls', 'Barley Risotto', 'Walnut Ravioli with Artichokes and Tomatoes'] +vegetarian_appetizers = ['Cambodian-Style Vegetable Spring Rolls', 'Summer Minestrone Cups', 'Asparagus Puffs', 'Grilled Tofu Tacos', 'Cambodian-Style Vegetable Spring Rolls', 'Grilled Tofu Tacos'] +vegetarian_dishes = ['Walnut Ravioli with Artichokes and Tomatoes', 'Mushroom Lasagna', 'Fried Zucchini with Balsamic and Chili Dressing', 'Barley Risotto', 'Nut Wellington', 'Cherry Tomato, Watercress and Fava Bean Salad', 'Roast Pumpkin and Lentil Salad with Roasted Lemon Dressing', 'Fresh Garden Peas over Cauliflower Almond Puree'] +vegetarian_appetizer_names = ['Cambodian-Style Vegetable Spring Rolls','Summer Minestrone Cups','Asparagus Puffs','Grilled Tofu Tacos'] + + +paleo = ['Zucchini Fritters with Lemon-Thyme Coconut Yogurt', 'Avocado Deviled Eggs', 'Grilled Flank Steak with Caesar Salad', 'Pumpkin Bread Crostini', 'BLT Bites', 'Roasted Chicken with Roasted Tomatoes, Avocado, and Sweet Potatoes', 'Chicken with Tamarind and Apricot Sauce', 'Grilled Fish Tacos with Cauliflower Tortillas', 'Grilled Pork Chops with Mango Pineapple Salsa', 'Grilled Shrimp and Pesto over Zucchini Noodles', 'Zucchini Fritters with Lemon-Thyme Coconut Yogurt', 'Pumpkin Bread Crostini', 'Chicken with Tamarind and Apricot Sauce', 'Grilled Shrimp and Pesto over Zucchini Noodles'] +paleo_appetizers = ['Zucchini Fritters with Lemon-Thyme Coconut Yogurt', 'Avocado Deviled Eggs', 'Pumpkin Bread Crostini', 'BLT Bites', 'Zucchini Fritters with Lemon-Thyme Coconut Yogurt', 'BLT Bites'] +paleo_dishes = ['Roasted Chicken with Roasted Tomatoes, Avocado, and Sweet Potatoes', 'Grilled Flank Steak with Caesar Salad', 'Grilled Fish Tacos with Cauliflower Tortillas', 'Grilled Pork Chops with Mango Pineapple Salsa', 'Grilled Shrimp and Pesto over Zucchini Noodles', 'Chicken with Tamarind and Apricot Sauce'] +paleo_appetizer_names = ['Zucchini Fritters with Lemon-Thyme Coconut Yogurt','Avocado Deviled Eggs','Pumpkin Bread Crostini','BLT Bites'] + + +keto = ['Cauliflower Pizza with Roasted Tomatoes and Chicken', 'Flank Steak with Chimichurri and Asparagus', 'Kingfish Lettuce Cups', 'Butter Chicken with Grilled Mushrooms, Brussel Sprouts and Mango Chutney', 'Prawn and Herb Omelette', 'Satay Steak Skewers', 'Parmesan Crackers and Spinach Crackers with Salmon Pate', 'Pork Chops with Grilled Castelfranco Radicchio and Asparagus', 'Seared Salmon with Pickled Vegetable and Watercress Salad', 'Braised Pork Belly with Apple Salad', 'Cauliflower Pizza with Roasted Tomatoes and Chicken', 'Butter Chicken with Grilled Mushrooms, Brussel Sprouts and Mango Chutney', 'Parmesan Crackers and Spinach Crackers with Salmon Pate', 'Braised Pork Belly with Apple Salad'] +keto_appetizers = ['Kingfish Lettuce Cups', 'Prawn and Herb Omelette', 'Satay Steak Skewers', 'Parmesan Crackers and Spinach Crackers with Salmon Pate', 'Kingfish Lettuce Cups', 'Parmesan Crackers and Spinach Crackers with Salmon Pate'] +keto_dishes = ['Cauliflower Pizza with Roasted Tomatoes and Chicken', 'Butter Chicken with Grilled Mushrooms, Brussel Sprouts and Mango Chutney', 'Braised Pork Belly with Apple Salad', 'Seared Salmon with Pickled Vegetable and Watercress Salad', 'Pork Chops with Grilled Castelfranco Radicchio and Asparagus', 'Flank Steak with Chimichurri and Asparagus'] +keto_appetizer_names = ['Kingfish Lettuce Cups','Prawn and Herb Omelette','Satay Steak Skewers','Parmesan Crackers and Spinach Crackers with Salmon Pate'] + + +omnivore = ['Beachside Snapper', 'Governor Shrimp Tacos', 'Shrimp, Bacon and Crispy Chickpea Tacos with Salsa de Guacamole', 'Burnt Masala Wings with Classic Coleslaw', 'Dahi Puri with Black Chickpeas', 'Brisket with Grilled Rhubarb, Onions, and Fennel', 'Roast Leg of Lamb with Crispy Moroccan Carrots & Couscous', 'Baked Chicken Jollof Rice', 'Seafood Risotto', 'Lamb over Marinated Summer Squash with Hazelnuts and Ricotta', 'Beachside Snapper', 'Burnt Masala Wings with Classic Coleslaw', 'Roast Leg of Lamb with Crispy Moroccan Carrots & Couscous', 'Lamb over Marinated Summer Squash with Hazelnuts and Ricotta'] +omnivore_appetizers = ['Governor Shrimp Tacos', 'Burnt Masala Wings with Classic Coleslaw', 'Dahi Puri with Black Chickpeas', 'Seafood Risotto', 'Governor Shrimp Tacos', 'Seafood Risotto'] +omnivore_dishes = ['Lamb over Marinated Summer Squash with Hazelnuts and Ricotta', 'Shrimp, Bacon and Crispy Chickpea Tacos with Salsa de Guacamole', 'Brisket with Grilled Rhubarb, Onions, and Fennel', 'Roast Leg of Lamb with Crispy Moroccan Carrots & Couscous', 'Beachside Snapper', 'Baked Chicken Jollof Rice'] +omnivore_appetizer_names = ['Governor Shrimp Tacos','Burnt Masala Wings with Classic Coleslaw','Dahi Puri with Black Chickpeas','Seafood Risotto'] + + +dishes_and_appetizers = ((vegan, vegan_appetizers), + (vegetarian, vegetarian_appetizers), + (paleo, paleo_appetizers), + (keto, keto_appetizers), + (omnivore, omnivore_appetizers) + ) + +dishes_cleaned = (vegan_dishes, + vegetarian_dishes, + paleo_dishes, + keto_dishes, + omnivore_dishes + ) + + +####################################### +# Data for test_singleton_ingredients # +####################################### + + +intersections = (VEGAN_INTERSECTIONS, VEGETARIAN_INTERSECTIONS, PALEO_INTERSECTIONS, + KETO_INTERSECTIONS, OMNIVORE_INTERSECTIONS) + +dishes_and_overlap = [(item[0], item[1]) for item in zip(ingredients_only, intersections)] +ingredients = (set.union(*group) for group in ingredients_only) +singletons = (item[0] ^ item[1] for item in zip(ingredients, intersections)) + +backup_singletons = [{'black-eyed peas', 'coriander', 'cashews', 'yellow split peas', 'pomegranate seeds', 'cumin', 'mangoes', 'pomegranate concentrate', 'red chili powder', 'slivered almonds', 'black peppercorn', 'cornstarch', 'smoked tofu', 'curry leaves', 'zucchini', 'currants', 'dried cranberries', 'yukon gold potato', 'tofu', 'yeast', 'fresh basil', 'hot water', 'ripe plantains', 'calabash nutmeg', 'green beans', 'kosher salt', 'grains of selim', 'vegetarian worcestershire sauce', 'cumin seeds', 'figs', 'ground turmeric', 'white rice', 'harissa', 'garlic powder', 'scallions', 'barberries', 'walnuts', 'basmati rice', 'saffron powder', 'butternut squash', 'thyme', 'tomato', 'chopped parsley', 'hing', 'coriander seeds', 'turmeric powder', 'eggplants', 'sesame oil', "za'atar", 'pareve puff pastry', 'firm tofu', 'yellow onions', 'coriander powder', 'parsley', 'garlic paste', 'rice vinegar', 'sorghum stems', 'spring onions', 'raisins', 'chinese eggplants', 'garam masala', 'ground almonds', 'baking soda', 'clove powder', 'allspice powder', 'parev shortcrust pastry', 'dill', 'nigella seeds', 'dried blueberries', 'cardamom powder', 'cilantro', 'serrano chili', 'breadcrumbs', 'mango powder', 'dried cherries', 'oregano', 'fresh red chili', 'pecans', 'chives', 'spaghetti', 'mixed herbs', 'brandy', 'cumin powder', 'silken tofu', 'yellow onion', 'balsamic vinegar', 'persian cucumber', 'red bell pepper', 'peanuts', 'siracha', 'red pepper flakes', 'spring onion', 'vegan unsweetened yoghurt', 'corn', 'khmeli suneli', 'barley malt', 'green onions', 'apples', 'corn flour', 'honey', 'celeriac', 'bulgur', 'sesame seeds', 'mashed potatoes', 'chili flakes', 'vegetable oil'}, +{'vegetarian fish sauce', 'cashews', 'white wine', 'portobello mushrooms', 'marmite', 'dates', 'tomatillos', 'cumin', 'chestnuts', 'beets', 'masa', 'mint', 'smoked tofu', 'fresh pea tendrils', 'puff pastry sheets', 'zucchini', 'currants', 'hazelnuts', 'croutons', 'pearl barley', 'dijon mustard', 'yukon gold potato', 'fresh tomatoes', 'vermicelli noodles', 'fresh cherry tomatoes', 'celery', 'hot water', 'green beans', 'grated nutmeg', 'roasted corn', 'palm sugar', 'ancho chili', 'fresh corn', 'spring roll wrappers', 'cotija cheese', 'parmesan rind', 'pasta sheets', 'brazil nuts', 'cauliflower', 'butternut squash', 'mint leaves', 'fresh cherry bocconcini', 'crema', 'blue cheese', 'chickpeas', 'pasilla chili', 'black beans', 'wombok', 'capers', 'pine nuts', 'egg', 'shiitake mushrooms', 'red thai chili', 'jalapeño chili', 'toasted peanuts', 'brussel sprouts', 'lime juice', 'leeks', 'flour', 'dried lasagna noodles', 'onions', 'limes', 'chipotle chili', 'lacinato kale', 'fresh pumpkin', 'almonds', 'olives', 'onion', 'fresh artichoke hearts', 'leek', 'pecans', 'chives', 'blanched almonds', 'nutmeg', 'fresh or frozen fava beans', 'soy sauce', 'avocados', 'bean sprouts', 'asparagus', 'feta cheese', 'sharp white cheddar', 'apples', 'sunflower oil', 'corn flour', 'avocado', 'puff pastry', 'red cabbage', 'pomegranate', 'fresh cilantro leaves', 'oil marinated artichokes', 'vegetable oil'}, +{'treviso', 'cashews', 'mexican oregano', 'pumpkin puree', 'purple sweet potato', 'homemade apricot honey preserves', 'apple cider vinegar', 'homemade tamarind concentrate', 'paleo parmesan cheese', 'pineapple', 'green bell pepper', 'chipotles', 'nutmeg', 'ground cumin', 'coconut yogurt', 'kale', 'mangoes', 'red bell pepper', 'dried apricots', 'garlic powder', 'pepitas', 'white vinegar', 'scallions', 'avocados', 'shredded red cabbage', 'smoked paprika', 'lime juice', 'flank steak', 'fresh parsley', 'shallots', 'chiles de árbol', 'yellow bell pepper', 'white chicken', 'whole chicken', 'chili powder', 'bacon', 'avocado mayonnaise', 'cilantro', 'limes', 'lemons', 'green onions', 'avocado oil', 'cloves', 'lacinato kale', 'lime zest', 'paleo mayonnaise', 'radishes', 'mango', 'dijon mustard', 'mustard seed', 'cider vinegar', 'pork chops', 'castelfranco radicchio', 'water', 'allspice', 'seranno chili', 'cilantro leaves', 'onion', 'tilapia', 'fresh cilantro leaves', 'worcestershire sauce', 'almond butter', 'fresh thai chili', 'fresh red chili', 'chives', 'roma tomatoes'}, +{'dried fenugreek leaves', 'apple cider vinegar', 'cinnamon sticks', 'roasted chicken', 'cumin', 'mangoes', 'heavy cream', 'micro cilantro', 'white vinegar', 'red chili powder', 'cinnamon powder', 'mustard seeds', 'red wine vinegar', 'mirin', 'cinnamon', 'green chili', 'avocado oil', 'curry leaves', 'star anise', 'dijon mustard', 'crunchy peanut butter', 'grilled king fish', 'chicken', 'fresh basil', 'cashew nuts', 'pink peppercorns', 'pork belly', 'spinach', 'watercress', 'whole small crimini mushrooms', 'coconut flour', 'fresh ginger', 'fennel bulb', 'harissa', 'tahini', 'mozzarella cheese', 'scallions', 'sriacha', 'fresh parsley', 'thyme', 'light soy sauce', 'cream cheese', 'hing', 'coriander seeds', 'sour cream', 'turmeric powder', 'castelfranco radicchio', 'parmesan', 'toasted buckwheat', 'coriander powder', 'dark soy sauce', 'granny smith apples', 'parsley', 'shrimp', 'garlic paste', 'roasted peanuts', 'turmeric', 'carrot', 'garam masala', 'clove powder', 'cucumbers', 'tomato paste', 'almond meal', 'dutch carrot', 'brussel sprouts', 'red and green thai chili', 'shallots', 'nigella seeds', 'cardamom powder', 'watermelon radishes', 'flaxmeal', 'cilantro', 'fennel seeds', 'chipotle chili', 'ghee', 'parmesan cheese', 'radishes', 'pork chops', 'cilantro leaves', 'fresh greek yogurt', 'cardamom', 'mango powder', 'onion', 'oregano', 'fresh red chili', 'pecans', 'salmon fillets', 'basil', 'green cabbage', 'cumin powder', 'almond flour', 'lemon', 'boned chicken', 'oyster sauce', 'soy sauce', 'little gem lettuce heads', 'peanut oil', 'peanuts', 'caster sugar', 'salmon steaks', 'ginger garlic paste', 'green onions', 'vinegar', 'cloves', 'kecap manis', 'avocado', 'chili flakes', 'red chili flakes', 'tomatoes'}, +{'coriander', 'white wine', 'fish stock', 'apple cider vinegar', 'salsa', 'rhubarb', 'beef brisket', 'cinnamon sticks', 'cumin', 'roasted chicken', 'chicken wings', 'white vinegar', 'sriracha', 'slivered almonds', 'fresh thyme', 'scotch bonnet pepper', 'zucchini', 'hazelnuts', 'pani puri', 'yukon gold potato', 'toasted bread', 'chicken', 'yoghurt', 'maggi cubes', 'couscous', 'roma tomatoes', 'celery seeds', 'chaat masala', 'white pepper', 'black cardamom', 'harissa', 'red snapper', 'green cardamom', 'crushed red pepper flakes', 'tahini', 'mexican crema', 'chiles de árbol', 'tomato', 'baby squid', 'mussels', 'chipotle adobo sauce', 'shelled large shrimp', 'tomato puree', 'chickpeas', 'fresh tortillas', 'flat-leaf parsley', 'anaheim chili', 'parsley', 'shrimp', 'chile manzano', 'vegetable bullion', 'prawns', 'cherry tomatoes', 'marjoram', 'beer', 'green bell pepper', 'date syrup', 'guajillo chile', 'baby scallops', 'yellow mustard', 'black chickpeas', 'bell pepper', 'filo pastry', 'thin sev', 'bacon', 'white wine vinegar', 'limes', 'rice', 'serrano chili', 'brown sugar', 'parmesan cheese', 'poblano chili', 'fennel bulbs', 'clams', 'baby carrot', 'arborio risotto rice', 'oregano', 'oaxaca cheese', 'green cabbage', 'yellow onion', 'balsamic vinegar', 'whole-milk yogurt', 'sugar', 'red bell pepper', 'pepitas', 'red pepper flakes', 'oranges', 'yellow bell pepper', 'summer squash', 'cloves', 'red cabbage', 'black peppercorns', 'fresh ricotta', 'crab legs', 'scallion chutney', 'sesame seeds', 'vegetable oil'}] \ No newline at end of file diff --git a/python/chaitanas-colossal-coaster/.exercism/config.json b/python/chaitanas-colossal-coaster/.exercism/config.json new file mode 100644 index 0000000..5374c4d --- /dev/null +++ b/python/chaitanas-colossal-coaster/.exercism/config.json @@ -0,0 +1,24 @@ +{ + "authors": [ + "mohanrajanr", + "BethanyG" + ], + "contributors": [ + "BethanyG", + "valentin-p", + "pranasziaukas" + ], + "files": { + "solution": [ + "list_methods.py" + ], + "test": [ + "list_methods_test.py" + ], + "exemplar": [ + ".meta/exemplar.py" + ] + }, + "icon": "spiral-matrix", + "blurb": "Learn useful list methods helping Chaitana manage the lines for her colossal roller coaster." +} diff --git a/python/chaitanas-colossal-coaster/.exercism/metadata.json b/python/chaitanas-colossal-coaster/.exercism/metadata.json new file mode 100644 index 0000000..d2d1567 --- /dev/null +++ b/python/chaitanas-colossal-coaster/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"chaitanas-colossal-coaster","id":"74ca4126d16e47bc872cd9fcc30f6d12","url":"https://exercism.org/tracks/python/exercises/chaitanas-colossal-coaster","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/chaitanas-colossal-coaster/HELP.md b/python/chaitanas-colossal-coaster/HELP.md new file mode 100644 index 0000000..0f5ca33 --- /dev/null +++ b/python/chaitanas-colossal-coaster/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +
+ +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit list_methods.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/chaitanas-colossal-coaster/HINTS.md b/python/chaitanas-colossal-coaster/HINTS.md new file mode 100644 index 0000000..df85ae9 --- /dev/null +++ b/python/chaitanas-colossal-coaster/HINTS.md @@ -0,0 +1,39 @@ +# Hints + +- Make sure you have a good understanding of how to create and update lists. +- The Python [documentation on `lists`][python lists] can be really helpful. +- The Python [tutorial section on `lists`][more on lists] is also a good resource. + +## 1. Add Me to the queue + +- An `if-else` statement can help you find which ticket type you are dealing with. +- You can then `append()` the person to the queue based on the ticket type. + +## 2. Where are my friends + +- You need to find the `index()` of the friend name from the queue. + +## 3. Can I please join them? + +- Since you know the `index()`, you can `insert()` the friend into the queue at that point. + +## 4. Mean person in the queue + +- You know the mean persons name, so you can `remove()` them from the queue. + +## 5. Namefellows + +- `count()`-ing the occurrences of the `name` in the queue could be a good strategy here. + +## 6. Remove the last person + +- Although you could `remove()` the person by name, `pop()`-ing them out might be quicker. + +## 7. Sort the Queue List + +- Don't forget that You need to avoid mutating the queue and losing its original order. +- Once you have a `copy()`, `sort()`-ing should be straightforward. +- We're looking for an _ascending_ sort, or _alphabetical from a-z_. + +[python lists]: https://docs.python.org/3.11/library/stdtypes.html#list +[more on lists]: https://docs.python.org/3.11/tutorial/datastructures.html#more-on-lists \ No newline at end of file diff --git a/python/chaitanas-colossal-coaster/README.md b/python/chaitanas-colossal-coaster/README.md new file mode 100644 index 0000000..d356814 --- /dev/null +++ b/python/chaitanas-colossal-coaster/README.md @@ -0,0 +1,419 @@ +# Chaitana's Colossal Coaster + +Welcome to Chaitana's Colossal Coaster on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. +If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :) + +## Introduction + +A [`list`][list] is a mutable collection of items in _sequence_. + Like most collections (_see the built-ins [`tuple`][tuple], [`dict`][dict] and [`set`][set]_), lists can hold reference to any (or multiple) data type(s) - including other lists. + Lists can be copied in whole or in part via [slice notation][slice notation] or through the use of `.copy()`. + Like any [sequence][sequence type], elements within `lists` are referenced by `0-based index` number from the left, or `-1-based index` number from the right. + +Lists support both [common][common sequence operations] and [mutable][mutable sequence operations] sequence operations such as `min()`/`max()`, `.index()`, `.append()` and `.reverse()`. + Elements inside a `list` can be iterated over using the `for item in ` construct. + `for index, item in enumerate()` can be used when both the element index and element value are needed. + +Python also provides many useful [list-methods][list-methods] for working with lists. + A selection of these `list methods` is covered below. + + +Note that when you manipulate a `list` with a `list-method`, **you alter the list** object that has been passed. + If you do not wish to mutate the original `list`, you will need to at least make a `shallow copy` of it via slice or `.copy()`. + + +## Adding Items + +To add an item to the end or "right-hand side" of an existing list, use `.append()`: + +```python +>>> numbers = [1, 2, 3] +>>> numbers.append(9) + +>>> numbers +[1, 2, 3, 9] +``` + +Rather than _appending_, `.insert()` gives you the ability to add the item to a _specific index_ in the list. +It takes 2 parameters: + +1. the `` at which you want the item to be inserted. +2. the `` to be inserted. + +**Note**: If the given `index` is 0, the item will be added to the start ("left-hand side") of the `list`. + If the supplied `index` is greater than the final `index` on the `list`, the item will be added in the final position -- the equivalent of using `.append()`. + + +```python +>>> numbers = [1, 2, 3] +>>> numbers.insert(0, -2) + +>>> numbers +[-2, 1, 2, 3] + +>>> numbers.insert(1, 0) + +>>> numbers +[-2, 0, 1, 2, 3] +``` + + +`.extend()` can be used to combine an existing list with the elements from another iterable (for example, a `set`, `tuple`, `str`, or `list`). + The iterable is _unpacked_ and elements are appended in order (_Using `.append()` in this circumstance would add the entire iterable as a **single item**._). + + +```python +>>> numbers = [1, 2, 3] +>>> other_numbers = [5, 6, 7] + +>>> numbers.extend(other_numbers) + +>>> numbers +[1, 2, 3, 5, 6, 7] + +>>> numbers.extend([8, 9]) + +>>> numbers +[1, 2, 3, 5, 6, 7, 8, 9] + +>>> numbers.append([8,9]) + +>>> numbers +[1, 2, 3, 5, 6, 7, 8, 9, [8, 9]] +``` + + +## Removing Items + +To delete an item from a list use `.remove()`, passing the item to be removed as an argument. + `.remove()` will throw a `ValueError` if the item is not present in the `list`. + + +```python +>>> numbers = [1, 2, 3] +>>> numbers.remove(2) + +>>> numbers +[1, 3] + +# Trying to remove a value that is not in the list throws a ValueError +>>> numbers.remove(0) +ValueError: list.remove(x): x not in list +``` + + +Alternatively, using the `.pop()` method will both remove **and** `return` an element for use. + + +`.pop()` takes one optional parameter: the `index` of the item to be removed and returned. + If the (optional) `index` argument is not specified, the final element of the `list` will be removed and returned. + If the `index` specified is higher than the final item `index`, an `IndexError` is raised. + + +```python +>>> numbers = [1, 2, 3] + +>>> numbers.pop(0) +1 + +>>> numbers +[2, 3] + +>>> numbers.pop() +3 + +>>> numbers +[2] + +>>> numbers.pop(1) +Traceback (most recent call last): + File "", line 1, in +IndexError: pop index out of range +``` + +All elements can be removed from a `list` with `list.clear()`. It doesn't take any parameters. + +```python +>>> numbers = [1, 2, 3] +>>> numbers.clear() + +>>> numbers +[] +``` + +## Reversing and reordering + +The `.reverse()` method will reverse the order of elements **in-place**. + + +```python +>>> numbers = [1, 2, 3] +>>> numbers.reverse() + +>>> numbers +[3, 2, 1] +``` + + +A list can be re-ordered _**in place**_ with the help of [`.sort()`][sort]. +Default sort order is _ascending_ from the left. +The Python docs offer [additional tips and techniques for sorting][sorting how to]. + +~~~~exercism/note + From 2002 to 2022, Python used an algorithm called [`Timsort`][timsort] internally to arrange lists, but switched to [`Powersort`][powersort] from `Python 3.11` onward. + +[powersort]: https://www.wild-inter.net/publications/munro-wild-2018 +[timsort]: https://en.wikipedia.org/wiki/Timsort +~~~~ + + +```python +>>> names = ["Tony", "Natasha", "Thor", "Bruce"] + +# The default sort order is *ascending*. +>>> names.sort() + +>>> names +["Bruce", "Natasha", "Thor", "Tony"] +``` + +If a _descending_ order is desired, pass the `reverse=True` argument: + +```python +>>> names = ["Tony", "Natasha", "Thor", "Bruce"] +>>> names.sort(reverse=True) + +>>> names +["Tony", "Thor", "Natasha", "Bruce"] +``` + +For cases where mutating the original list is undesirable, the built-in [`sorted()`][sorted] function can be used to return a sorted **copy**. + + +```python +>>> names = ["Tony", "Natasha", "Thor", "Bruce"] + +>>> sorted(names) +['Bruce', 'Natasha', 'Thor', 'Tony'] +``` + + +## Occurrences of an item in a list + +The number of occurrences of an element in a list can be calculated with the help of `list.count()`. + It takes the `item` to be counted as its argument and returns the total number of times that element appears in the `list`. + + +```python +>>> items = [1, 4, 7, 8, 2, 9, 2, 1, 1, 0, 4, 3] + +>>> items.count(1) +3 +``` + +## Finding the index of items + +`.index()` will return the `index` number of the _first occurrence_ of an item passed in. + If there are no occurrences, a `ValueError` is raised. + If the exact position of an item isn't needed, the built-in `in` operator is more efficient for checking if a list contains a given value. + + +Indexing is zero-based from the left, so the position of the "first" item is `0`. +Indexing will also work from the right, beginning with `-1`. + + +```python +>>> items = [7, 4, 1, 0, 2, 5] + +>>> items.index(4) +1 + +>>> items.index(10) +ValueError: 10 is not in list +``` + +`start` and `end` indices can also be provided to narrow the search to a specific section of the `list`: + +```python +>>> names = ["Tina", "Leo", "Thomas", "Tina", "Emily", "Justin"] + +>>> names.index("Tina") +0 + +>>> names.index("Tina", 2, 5) +3 +``` + +[common sequence operations]: https://docs.python.org/3/library/stdtypes.html#common-sequence-operations +[dict]: https://docs.python.org/3/library/stdtypes.html#dict +[list-methods]: https://docs.python.org/3/tutorial/datastructures.html#more-on-lists +[list]: https://docs.python.org/3/library/stdtypes.html#list +[mutable sequence operations]: https://docs.python.org/3/library/stdtypes.html#typesseq-mutable +[sequence type]: https://docs.python.org/3/library/stdtypes.html#sequence-types-list-tuple-range +[set]: https://docs.python.org/3/library/stdtypes.html#set +[slice notation]: https://docs.python.org/3/reference/expressions.html#slicings +[sort]: https://docs.python.org/3/library/stdtypes.html#list.sort +[sorted]: https://docs.python.org/3/library/functions.html#sorted +[sorting how to]: https://docs.python.org/3/howto/sorting.html +[tuple]: https://docs.python.org/3/library/stdtypes.html#tuple + +## Instructions + +Chaitana owns a very popular theme park. + She only has one ride in the very center of beautifully landscaped grounds: The Biggest Roller Coaster in the World(TM). + Although there is only this one attraction, people travel from all over the world and stand in line for hours for the opportunity to ride Chaitana's hypercoaster. + +There are two queues for this ride, each represented as a `list`: + +1. Normal Queue +2. Express Queue (_also known as the Fast-track_) - where people pay extra for priority access. + + +You have been asked to write some code to better manage the guests at the park. + You need to implement the following functions as soon as possible before the guests (and your boss, Chaitana!) get cranky. + Make sure you read carefully. + Some tasks ask that you change or update the existing queue, while others ask you to make a copy of it. + + +## 1. Add me to the queue + +Define the `add_me_to_the_queue()` function that takes 4 parameters `, , , ` and returns the appropriate queue updated with the person's name. + + +1. `` is an `int` with 1 == express_queue and 0 == normal_queue. +2. `` is the name (as a `str`) of the person to be added to the respective queue. + + +```python +>>> add_me_to_the_queue(express_queue=["Tony", "Bruce"], normal_queue=["RobotGuy", "WW"], ticket_type=1, person_name="RichieRich") +... +["Tony", "Bruce", "RichieRich"] + +>>> add_me_to_the_queue(express_queue=["Tony", "Bruce"], normal_queue=["RobotGuy", "WW"], ticket_type=0, person_name="HawkEye") +.... +["RobotGuy", "WW", "HawkEye"] +``` + +## 2. Where are my friends? + +One person arrived late at the park but wants to join the queue where their friends are waiting. + But they have no idea where their friends are standing and there isn't any phone reception to call them. + +Define the `find_my_friend()` function that takes 2 parameters `queue` and `friend_name` and returns the position in the queue of the person's name. + + +1. `` is the `list` of people standing in the queue. +2. `` is the name of the friend whose index (place in the queue) you need to find. + +Remember: Indexing starts at 0 from the left, and -1 from the right. + + +```python +>>> find_my_friend(queue=["Natasha", "Steve", "T'challa", "Wanda", "Rocket"], friend_name="Steve") +... +1 +``` + + +## 3. Can I please join them? + +Now that their friends have been found (in task #2 above), the late arriver would like to join them at their place in the queue. +Define the `add_me_with_my_friends()` function that takes 3 parameters `queue`, `index`, and `person_name`. + + +1. `` is the `list` of people standing in the queue. +2. `` is the position at which the new person should be added. +3. `` is the name of the person to add at the index position. + +Return the queue updated with the late arrivals name. + + +```python +>>> add_me_with_my_friends(queue=["Natasha", "Steve", "T'challa", "Wanda", "Rocket"], index=1, person_name="Bucky") +... +["Natasha", "Bucky", "Steve", "T'challa", "Wanda", "Rocket"] +``` + +## 4. Mean person in the queue + +You just heard from the queue that there is a really mean person shoving, shouting, and making trouble. + You need to throw that miscreant out for bad behavior! + + +Define the `remove_the_mean_person()` function that takes 2 parameters `queue` and `person_name`. + + +1. `` is the `list` of people standing in the queue. +2. `` is the name of the person that needs to be kicked out. + +Return the queue updated without the mean person's name. + +```python +>>> remove_the_mean_person(queue=["Natasha", "Steve", "Eltran", "Wanda", "Rocket"], person_name="Eltran") +... +["Natasha", "Steve", "Wanda", "Rocket"] +``` + + +## 5. Namefellows + +You may not have seen two unrelated people who look exactly the same, but you have _definitely_ seen unrelated people with the exact same name (_namefellows_)! + Today, it looks like there are a lot of them in attendance. + You want to know how many times a particular name occurs in the queue. + +Define the `how_many_namefellows()` function that takes 2 parameters `queue` and `person_name`. + +1. `` is the `list` of people standing in the queue. +2. `` is the name you think might occur more than once in the queue. + + +Return the number of occurrences of `person_name`, as an `int`. + + +```python +>>> how_many_namefellows(queue=["Natasha", "Steve", "Eltran", "Natasha", "Rocket"], person_name="Natasha") +... +2 +``` + +## 6. Remove the last person + +Sadly, it's overcrowded at the park today and you need to remove the last person in the normal line (_you will give them a voucher to come back in the fast-track on another day_). + You will have to define the function `remove_the_last_person()` that takes 1 parameter `queue`, which is the list of people standing in the queue. + +You should update the `list` and also `return` the name of the person who was removed, so you can write them a voucher. + + +```python +>>> remove_the_last_person(queue=["Natasha", "Steve", "Eltran", "Natasha", "Rocket"]) +... +'Rocket' +``` + +## 7. Sort the Queue List + +For administrative purposes, you need to get all the names in a given queue in alphabetical order. + + +Define the `sorted_names()` function that takes 1 argument, `queue`, (the `list` of people standing in the queue), and returns a `sorted` copy of the `list`. + + +```python +>>> sorted_names(queue=["Natasha", "Steve", "Eltran", "Natasha", "Rocket"]) +... +['Eltran', 'Natasha', 'Natasha', 'Rocket', 'Steve'] +``` + +## Source + +### Created by + +- @mohanrajanr +- @BethanyG + +### Contributed to by + +- @BethanyG +- @valentin-p +- @pranasziaukas \ No newline at end of file diff --git a/python/chaitanas-colossal-coaster/__pycache__/list_methods.cpython-313.pyc b/python/chaitanas-colossal-coaster/__pycache__/list_methods.cpython-313.pyc new file mode 100644 index 0000000..dcde05b Binary files /dev/null and b/python/chaitanas-colossal-coaster/__pycache__/list_methods.cpython-313.pyc differ diff --git a/python/chaitanas-colossal-coaster/__pycache__/list_methods.cpython-314.pyc b/python/chaitanas-colossal-coaster/__pycache__/list_methods.cpython-314.pyc new file mode 100644 index 0000000..fb77cb1 Binary files /dev/null and b/python/chaitanas-colossal-coaster/__pycache__/list_methods.cpython-314.pyc differ diff --git a/python/chaitanas-colossal-coaster/__pycache__/list_methods_test.cpython-313-pytest-8.3.4.pyc b/python/chaitanas-colossal-coaster/__pycache__/list_methods_test.cpython-313-pytest-8.3.4.pyc new file mode 100644 index 0000000..f92b392 Binary files /dev/null and b/python/chaitanas-colossal-coaster/__pycache__/list_methods_test.cpython-313-pytest-8.3.4.pyc differ diff --git a/python/chaitanas-colossal-coaster/__pycache__/list_methods_test.cpython-314-pytest-9.1.0.pyc b/python/chaitanas-colossal-coaster/__pycache__/list_methods_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..2782a8d Binary files /dev/null and b/python/chaitanas-colossal-coaster/__pycache__/list_methods_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/chaitanas-colossal-coaster/list_methods.py b/python/chaitanas-colossal-coaster/list_methods.py new file mode 100644 index 0000000..38e30bf --- /dev/null +++ b/python/chaitanas-colossal-coaster/list_methods.py @@ -0,0 +1,87 @@ +"""Functions to manage and organize queues at Chaitana's roller coaster.""" + + +def add_me_to_the_queue(express_queue, normal_queue, ticket_type, person_name): + """Add a person to the 'express' or 'normal' queue depending on the ticket number. + + :param express_queue: list - names in the Fast-track queue. + :param normal_queue: list - names in the normal queue. + :param ticket_type: int - type of ticket. 1 = express, 0 = normal. + :param person_name: str - name of person to add to a queue. + :return: list - the (updated) queue the name was added to. + """ + match ticket_type: + case 1: + express_queue.append(person_name) + return express_queue + case 0: + normal_queue.append(person_name) + return normal_queue + + +def find_my_friend(queue, friend_name): + """Search the queue for a name and return their queue position (index). + + :param queue: list - names in the queue. + :param friend_name: str - name of friend to find. + :return: int - index at which the friends name was found. + """ + for index, name in enumerate(queue): + if name == friend_name: + return index + return None + + +def add_me_with_my_friends(queue, index, person_name): + """Insert the late arrival's name at a specific index of the queue. + + :param queue: list - names in the queue. + :param index: int - the index at which to add the new name. + :param person_name: str - the name to add. + :return: list - queue updated with new name. + """ + queue.insert(index, person_name) + return queue + + +def remove_the_mean_person(queue, person_name): + """Remove the mean person from the queue by the provided name. + + :param queue: list - names in the queue. + :param person_name: str - name of mean person. + :return: list - queue update with the mean persons name removed. + """ + for index, name in enumerate(queue): + if name == person_name: + queue.pop(index) + return queue + + +def how_many_namefellows(queue, person_name): + """Count how many times the provided name appears in the queue. + + :param queue: list - names in the queue. + :param person_name: str - name you wish to count or track. + :return: int - the number of times the name appears in the queue. + """ + return queue.count(person_name) + + +def remove_the_last_person(queue): + """Remove the person in the last index from the queue and return their name. + + :param queue: list - names in the queue. + :return: str - name that has been removed from the end of the queue. + """ + return queue.pop() + + +def sorted_names(queue): + """Sort the names in the queue in alphabetical order and return the result. + + :param queue: list - names in the queue. + :return: list - copy of the queue in alphabetical order. + """ + queue.sort() + sorted_queue: list = queue.copy() + return sorted_queue diff --git a/python/chaitanas-colossal-coaster/list_methods_test.py b/python/chaitanas-colossal-coaster/list_methods_test.py new file mode 100644 index 0000000..7a754b7 --- /dev/null +++ b/python/chaitanas-colossal-coaster/list_methods_test.py @@ -0,0 +1,316 @@ +import unittest +from copy import deepcopy +import pytest + + +from list_methods import ( + add_me_to_the_queue, + find_my_friend, + add_me_with_my_friends, + remove_the_mean_person, + how_many_namefellows, + remove_the_last_person, + sorted_names, +) + + +class ListMethodsTest(unittest.TestCase): + @pytest.mark.task(taskno=1) + def test_add_me_to_the_queue(self): + test_data = [ + ((['Tony', 'Bruce'], ['RobotGuy', 'WW'], 0, 'HawkEye'), ['RobotGuy', 'WW', 'HawkEye']), + ((['Tony', 'Bruce'], ['RobotGuy', 'WW'], 1, 'RichieRich'), ['Tony', 'Bruce', 'RichieRich']), + ((['Agatha', 'Pepper', 'Valkyrie'], ['Drax', 'Nebula'], 1, 'Okoye'), ['Agatha', 'Pepper', 'Valkyrie', 'Okoye']), + ((['Agatha', 'Pepper', 'Valkyrie'], ['Drax', 'Nebula'], 0, 'Gamora'), ['Drax', 'Nebula', 'Gamora']), + ] + + for variant, (params, expected) in enumerate(test_data, start=1): + # Deepcopy() is needed here because the task expects the input lists to be mutated. + # That mutation wrecks havoc with the verification and error messaging. + express_queue, normal_queue, ticket_type, person_name = deepcopy(params) + + with self.subTest(f'variation #{variant}', params=params, expected=expected): + actual_result = add_me_to_the_queue(*params) + + error_message = ( + f'\nCalled add_me_to_the_queue{express_queue, normal_queue, ticket_type, person_name}.\n' + f'The function returned {actual_result},\n' + f' but the tests expected {expected} after {person_name} was added.') + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=1) + def test_add_me_to_the_queue_validate_queue(self): + test_data = [ + ((['Tony', 'Bruce'], ['RobotGuy', 'WW'], 0, 'HawkEye'), ['RobotGuy', 'WW', 'HawkEye']), + ((['Tony', 'Bruce'], ['RobotGuy', 'WW'], 1, 'RichieRich'), ['Tony', 'Bruce', 'RichieRich']), + ((['Agatha', 'Pepper', 'Valkyrie'], ['Drax', 'Nebula'], 1, 'Okoye'), ['Agatha', 'Pepper', 'Valkyrie', 'Okoye']), + ((['Agatha', 'Pepper', 'Valkyrie'], ['Drax', 'Nebula'], 0, 'Gamora'), ['Drax', 'Nebula', 'Gamora']), + ] + + for variant, (params, expected) in enumerate(test_data, start=1): + # Deepcopy() is needed here because the task expects the input lists to be mutated. + # That mutation wrecks havoc with the verification and error messaging. + express_queue, normal_queue, ticket_type, person_name = deepcopy(params) + express, normal, ticket, name = params + + with self.subTest(f'variation #{variant}', + express=express, normal=normal, + ticket=ticket, name=name, expected=expected): + + actual_result = add_me_to_the_queue(express, normal, ticket, name) + + if type == 1: + error_message = ( + f'\nCalled add_me_to_the_queue{express_queue, normal_queue, ticket_type, person_name}.\n' + f'The queue == {express}, but the tests expected\n' + f'queue == {expected} after {person_name} was added.' + ) + + self.assertIs(actual_result, express, msg=error_message) + + if type == 0: + error_message = ( + f'\nCalled add_me_to_the_queue{express_queue, normal_queue, ticket_type, person_name}.\n' + f'The queue == {normal}, but the tests expected \n' + f'queue == {expected} after {person_name} was added.' + ) + + self.assertIs(actual_result, normal, msg=error_message) + + @pytest.mark.task(taskno=2) + def test_find_my_friend(self): + test_data = [ + (['Natasha', 'Steve', 'Tchalla', 'Wanda', 'Rocket'], 'Natasha'), + (['Natasha', 'Steve', 'Tchalla', 'Wanda', 'Rocket'], 'Steve'), + (['Natasha', 'Steve', 'Tchalla', 'Wanda', 'Rocket'], 'Rocket'), + ] + + result_data = (0,1,4) + + for variant, (params, expected) in enumerate(zip(test_data, result_data), start=1): + with self.subTest(f'variation #{variant}', params=params, expected=expected): + actual_result = find_my_friend(*params) + error_message = ( + f'\nCalled find_my_friend{params}.\n' + f'The function returned {actual_result}, but\n' + f'the tests expected {expected} when looking for\n' + f'{params[-1]} in the queue.' + ) + + self.assertIs(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=3) + def test_add_me_with_my_friends(self): + test_data = [ + (['Natasha', 'Steve', 'Tchalla', 'Wanda', 'Rocket'], 0, 'Bucky'), + (['Natasha', 'Steve', 'Tchalla', 'Wanda', 'Rocket'], 1, 'Bucky'), + (['Natasha', 'Steve', 'Tchalla', 'Wanda', 'Rocket'], 5, 'Bucky'), + ] + + result_data = [ + ['Bucky', 'Natasha', 'Steve', 'Tchalla', 'Wanda', 'Rocket'], + ['Natasha', 'Bucky', 'Steve', 'Tchalla', 'Wanda', 'Rocket'], + ['Natasha', 'Steve', 'Tchalla', 'Wanda', 'Rocket', 'Bucky'], + ] + + for variant, (params, expected) in enumerate(zip(test_data, result_data), start=1): + # Deepcopy() is needed here because the task expects the input lists to be mutated. + # That mutation wrecks havoc with the verification and error messaging. + queue, index, person_name = deepcopy(params) + + with self.subTest(f'variation #{variant}', params=params, expected=expected): + + actual_result = add_me_with_my_friends(*params) + error_message = ( + f'\nCalled add_me_with_my_friends{queue, index, person_name}.\n' + f'The function returned {actual_result}, but\n' + f'the tests expected {expected} when adding\n' + f'{person_name} to position {index} in the queue.' + ) + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=3) + def test_add_me_with_my_friends_validate_queue(self): + test_data = [ + (['Natasha', 'Steve', 'Tchalla', 'Wanda', 'Rocket'], 0, 'Bucky'), + (['Natasha', 'Steve', 'Tchalla', 'Wanda', 'Rocket'], 1, 'Bucky'), + (['Natasha', 'Steve', 'Tchalla', 'Wanda', 'Rocket'], 5, 'Bucky'), + ] + + result_data = [ + ['Bucky', 'Natasha', 'Steve', 'Tchalla', 'Wanda', 'Rocket'], + ['Natasha', 'Bucky', 'Steve', 'Tchalla', 'Wanda', 'Rocket'], + ['Natasha', 'Steve', 'Tchalla', 'Wanda', 'Rocket', 'Bucky'], + ] + + for variant, (params, expected) in enumerate(zip(test_data, result_data), start=1): + # Deepcopy() is needed here because the task expects the input lists to be mutated. + # That mutation wrecks havoc with the verification and error messaging. + start_queue, add_index, person_name = deepcopy(params) + queue, _, _ = params + + with self.subTest(f'variation #{variant}', params=params, expected=expected): + actual_result = add_me_with_my_friends(*params) + error_message = ( + f'\nCalled add_me_with_my_friends{start_queue, add_index, person_name}.\n' + f'The function returned {actual_result},\n' + 'but the original queue was unmodified. The tests expected the \n' + f'*original* queue to be modified by adding "{person_name}".' + ) + + self.assertIs(actual_result, queue, msg=error_message) + + @pytest.mark.task(taskno=4) + def test_remove_the_mean_person(self): + test_data = [ + (['Natasha', 'Steve', 'Ultron', 'Wanda', 'Rocket'], 'Ultron'), + (['Natasha', 'Steve', 'Wanda', 'Rocket', 'Ultron'], 'Rocket'), + (['Ultron', 'Natasha', 'Steve', 'Wanda', 'Rocket'], 'Steve'), + ] + + result_data = [ + ['Natasha', 'Steve', 'Wanda', 'Rocket'], + ['Natasha', 'Steve', 'Wanda', 'Ultron'], + ['Ultron', 'Natasha', 'Wanda', 'Rocket'], + ] + + for variant, (params, expected) in enumerate(zip(test_data, result_data), start=1): + + # Deepcopy() is needed here because the task expects the input lists to be mutated. + # That mutation wrecks havoc with the verification and error messaging. + start_queue, person_name = deepcopy(params) + + with self.subTest(f'variation #{variant}', params=params, expected=expected): + actual_result = remove_the_mean_person(*params) + error_message = ( + f'\nCalled remove_the_mean_person{start_queue, person_name}.\n' + f'The function returned {actual_result}, but\n' + f'the tests expected {expected} when removing\n' + f'{person_name} from the queue.' + ) + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=4) + def test_remove_the_mean_person_validate_queue(self): + test_data = [ + (['Natasha', 'Steve', 'Ultron', 'Wanda', 'Rocket'], 'Ultron'), + (['Natasha', 'Steve', 'Wanda', 'Rocket', 'Ultron'], 'Rocket'), + (['Ultron', 'Natasha', 'Steve', 'Wanda', 'Rocket'], 'Steve'), + ] + + result_data = [ + ['Natasha', 'Steve', 'Wanda', 'Rocket'], + ['Natasha', 'Steve', 'Wanda', 'Ultron'], + ['Ultron', 'Natasha', 'Wanda', 'Rocket'], + ] + + + for variant, (params, expected) in enumerate(zip(test_data, result_data), start=1): + + # Deepcopy() is needed here because the task expects the input lists to be mutated. + # That mutation wrecks havoc with the verification and error messaging. + start_queue, person_name = deepcopy(params) + queue, _ = params + + with self.subTest(f'variation #{variant}', params=params, expected=expected): + actual_result = remove_the_mean_person(*params) + error_message = ( + f'\nCalled remove_the_mean_person{start_queue, person_name}.\n' + f'The function returned {actual_result}, queue == {queue}.\n' + f'But the tests expected queue == {expected} when removing\n' + f'{person_name}.' + ) + + self.assertIs(actual_result, queue, msg=error_message) + + + @pytest.mark.task(taskno=5) + def test_how_many_namefellows(self): + test_data = [(['Natasha', 'Steve', 'Ultron', 'Natasha', 'Rocket'], 'Bucky'), + (['Natasha', 'Steve', 'Ultron', 'Rocket'], 'Natasha'), + (['Natasha', 'Steve', 'Ultron', 'Natasha', 'Rocket'], 'Natasha')] + + result_data = (0,1,2) + + for variant, (params, expected) in enumerate(zip(test_data, result_data), start=1): + with self.subTest(f'variation #{variant}', params=params, expected=expected): + actual_result = how_many_namefellows(*params) + + error_message = (f'Called how_many_namefellows{params}. ' + f'The function returned {actual_result}, but ' + f'The tests expected {expected} when counting ' + f'namefellows in the queue for {params[-1]}.') + + self.assertIs(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=6) + def test_remove_the_last_person(self): + test_data = [ + (['Natasha', 'Steve', 'Ultron', 'Natasha', 'Rocket'], ['Natasha', 'Steve', 'Ultron', 'Natasha'], 'Rocket'), + (['Wanda', 'Natasha', 'Steve', 'Rocket', 'Ultron'], ['Wanda', 'Natasha', 'Steve', 'Rocket'], 'Ultron'), + (['Steve', 'Wanda', 'Rocket', 'Ultron', 'Natasha'], ['Steve', 'Wanda', 'Rocket', 'Ultron'], 'Natasha') + ] + for variant, (queue, modified, expected) in enumerate(test_data, start=1): + with self.subTest(f'variation #{variant}', queue=queue, modified=modified, expected=expected): + + # Deepcopy() is needed here because the task expects the input lists to be mutated. + # That mutation wrecks havoc with the verification and error messaging. + unmodified_queue = deepcopy(queue) + expected_result = expected + actual_result = remove_the_last_person(queue) + expected_queue = modified + + error_message = (f'\nCalled remove_the_last_person({unmodified_queue}).\n' + f'The function was expected to remove and return the name "{expected_result}" ' + f'and change the queue to {expected_queue},\n' + f'but the name "{actual_result}" was returned and the queue == {queue}.') + + self.assertEqual((actual_result, queue), (expected_result, expected_queue), msg=error_message) + + + @pytest.mark.task(taskno=7) + def test_sorted_names(self): + test_data =( + (['Steve', 'Ultron', 'Natasha', 'Rocket'], ['Natasha', 'Rocket', 'Steve', 'Ultron']), + (['Agatha', 'Pepper', 'Valkyrie', 'Drax', 'Nebula'], ['Agatha', 'Drax', 'Nebula', 'Pepper', 'Valkyrie']), + (['Gamora', 'Loki', 'Tony', 'Peggy', 'Okoye'], ['Gamora', 'Loki', 'Okoye', 'Peggy', 'Tony']), + ) + + for variant, (queue, expected) in enumerate(test_data, start=1): + with self.subTest(f'variation #{variant}', queue=queue, expected=expected): + actual_result = sorted_names(queue) + expected_result = expected + + error_message = (f'\nCalled sorted_names({queue}).\n' + f'The function returned {actual_result}, but \n' + f'the tests expect {expected_result}.') + + self.assertEqual(actual_result, expected_result, msg=error_message) + + @pytest.mark.task(taskno=7) + def test_sorted_names_validate_queue(self): + test_data = ( + (['Steve', 'Ultron', 'Natasha', 'Rocket'], ['Natasha', 'Rocket', 'Steve', 'Ultron']), + (['Agatha', 'Pepper', 'Valkyrie', 'Drax', 'Nebula'], ['Agatha', 'Drax', 'Nebula', 'Pepper', 'Valkyrie']), + (['Gamora', 'Loki', 'Tony', 'Peggy', 'Okoye'], ['Gamora', 'Loki', 'Okoye', 'Peggy', 'Tony']), + ) + + for variant, (queue, expected) in enumerate(test_data, start=1): + with self.subTest(f'variation #{variant}', queue=queue, expected=expected): + + # Deepcopy() is needed here because the input lists might be mutated. + # That mutation wrecks havoc with the verification and error messaging. + original_queue = deepcopy(queue) + actual_result = sorted_names(queue) + expected_result = expected + + error_message = (f'\nCalled sorted_names({original_queue}).\n' + f'The function returned {actual_result}, \n' + f'with a queue == {queue}.\n' + f'The tests expect {expected_result}, \n' + f'with a queue == {original_queue}.') + + self.assertIsNot(actual_result, queue, msg=error_message) diff --git a/python/collatz-conjecture/.exercism/config.json b/python/collatz-conjecture/.exercism/config.json new file mode 100644 index 0000000..cfed91f --- /dev/null +++ b/python/collatz-conjecture/.exercism/config.json @@ -0,0 +1,31 @@ +{ + "authors": [ + "zwaltman" + ], + "contributors": [ + "BethanyG", + "cmccandless", + "Dog", + "ikhadykin", + "K4cePhoenix", + "N-Parsons", + "smt923", + "Stigjb", + "thomasjpfan", + "tqa236" + ], + "files": { + "solution": [ + "collatz_conjecture.py" + ], + "test": [ + "collatz_conjecture_test.py" + ], + "example": [ + ".meta/example.py" + ] + }, + "blurb": "Calculate the number of steps to reach 1 using the Collatz conjecture.", + "source": "Wikipedia", + "source_url": "https://en.wikipedia.org/wiki/Collatz_conjecture" +} diff --git a/python/collatz-conjecture/.exercism/metadata.json b/python/collatz-conjecture/.exercism/metadata.json new file mode 100644 index 0000000..1d2fafd --- /dev/null +++ b/python/collatz-conjecture/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"collatz-conjecture","id":"27e309a996df4902b1f62e4d4af9540b","url":"https://exercism.org/tracks/python/exercises/collatz-conjecture","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/collatz-conjecture/HELP.md b/python/collatz-conjecture/HELP.md new file mode 100644 index 0000000..6b9b083 --- /dev/null +++ b/python/collatz-conjecture/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +
+ +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit collatz_conjecture.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/collatz-conjecture/README.md b/python/collatz-conjecture/README.md new file mode 100644 index 0000000..2e9c91c --- /dev/null +++ b/python/collatz-conjecture/README.md @@ -0,0 +1,73 @@ +# Collatz Conjecture + +Welcome to Collatz Conjecture on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Introduction + +One evening, you stumbled upon an old notebook filled with cryptic scribbles, as though someone had been obsessively chasing an idea. +On one page, a single question stood out: **Can every number find its way to 1?** +It was tied to something called the **Collatz Conjecture**, a puzzle that has baffled thinkers for decades. + +The rules were deceptively simple. +Pick any positive integer. + +- If it's even, divide it by 2. +- If it's odd, multiply it by 3 and add 1. + +Then, repeat these steps with the result, continuing indefinitely. + +Curious, you picked number 12 to test and began the journey: + +12 ➜ 6 ➜ 3 ➜ 10 ➜ 5 ➜ 16 ➜ 8 ➜ 4 ➜ 2 ➜ 1 + +Counting from the second number (6), it took 9 steps to reach 1, and each time the rules repeated, the number kept changing. +At first, the sequence seemed unpredictable — jumping up, down, and all over. +Yet, the conjecture claims that no matter the starting number, we'll always end at 1. + +It was fascinating, but also puzzling. +Why does this always seem to work? +Could there be a number where the process breaks down, looping forever or escaping into infinity? +The notebook suggested solving this could reveal something profound — and with it, fame, [fortune][collatz-prize], and a place in history awaits whoever could unlock its secrets. + +[collatz-prize]: https://mathprize.net/posts/collatz-conjecture/ + +## Instructions + +Given a positive integer, return the number of steps it takes to reach 1 according to the rules of the Collatz Conjecture. + +## Exception messages + +Sometimes it is necessary to [raise an exception](https://docs.python.org/3/tutorial/errors.html#raising-exceptions). When you do this, you should always include a **meaningful error message** to indicate what the source of the error is. This makes your code more readable and helps significantly with debugging. For situations where you know that the error source will be a certain type, you can choose to raise one of the [built in error types](https://docs.python.org/3/library/exceptions.html#base-classes), but should still include a meaningful message. + +The Collatz Conjecture is only concerned with **strictly positive integers**, so this exercise expects you to use the [raise statement](https://docs.python.org/3/reference/simple_stmts.html#the-raise-statement) and "throw" a `ValueError` in your solution if the given value is zero or a negative integer. The tests will only pass if you both `raise` the `exception` and include a message with it. + +To raise a `ValueError` with a message, write the message as an argument to the `exception` type: + +```python +# example when argument is zero or a negative integer +raise ValueError("Only positive integers are allowed") +``` + +## Source + +### Created by + +- @zwaltman + +### Contributed to by + +- @BethanyG +- @cmccandless +- @Dog +- @ikhadykin +- @K4cePhoenix +- @N-Parsons +- @smt923 +- @Stigjb +- @thomasjpfan +- @tqa236 + +### Based on + +Wikipedia - https://en.wikipedia.org/wiki/Collatz_conjecture \ No newline at end of file diff --git a/python/collatz-conjecture/__pycache__/collatz_conjecture.cpython-313.pyc b/python/collatz-conjecture/__pycache__/collatz_conjecture.cpython-313.pyc new file mode 100644 index 0000000..e7361ae Binary files /dev/null and b/python/collatz-conjecture/__pycache__/collatz_conjecture.cpython-313.pyc differ diff --git a/python/collatz-conjecture/__pycache__/collatz_conjecture.cpython-314.pyc b/python/collatz-conjecture/__pycache__/collatz_conjecture.cpython-314.pyc new file mode 100644 index 0000000..8c9d783 Binary files /dev/null and b/python/collatz-conjecture/__pycache__/collatz_conjecture.cpython-314.pyc differ diff --git a/python/collatz-conjecture/__pycache__/collatz_conjecture_test.cpython-313-pytest-8.3.4.pyc b/python/collatz-conjecture/__pycache__/collatz_conjecture_test.cpython-313-pytest-8.3.4.pyc new file mode 100644 index 0000000..b745095 Binary files /dev/null and b/python/collatz-conjecture/__pycache__/collatz_conjecture_test.cpython-313-pytest-8.3.4.pyc differ diff --git a/python/collatz-conjecture/__pycache__/collatz_conjecture_test.cpython-314-pytest-9.1.0.pyc b/python/collatz-conjecture/__pycache__/collatz_conjecture_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..aa2bda1 Binary files /dev/null and b/python/collatz-conjecture/__pycache__/collatz_conjecture_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/collatz-conjecture/collatz_conjecture.py b/python/collatz-conjecture/collatz_conjecture.py new file mode 100644 index 0000000..9be87eb --- /dev/null +++ b/python/collatz-conjecture/collatz_conjecture.py @@ -0,0 +1,12 @@ +def steps(number): + steps: int = 0 + if number <= 0: + raise ValueError("Only positive integers are allowed") + while number != 1: + steps += 1 + if (number % 2) == 0: + number /= 2 + else: + number *= 3 + number += 1 + return steps diff --git a/python/collatz-conjecture/collatz_conjecture_test.py b/python/collatz-conjecture/collatz_conjecture_test.py new file mode 100644 index 0000000..306e3db --- /dev/null +++ b/python/collatz-conjecture/collatz_conjecture_test.py @@ -0,0 +1,35 @@ +# These tests are auto-generated with test data from: +# https://github.com/exercism/problem-specifications/tree/main/exercises/collatz-conjecture/canonical-data.json +# File last updated on 2023-07-20 + +import unittest + +from collatz_conjecture import ( + steps, +) + + +class CollatzConjectureTest(unittest.TestCase): + def test_zero_steps_for_one(self): + self.assertEqual(steps(1), 0) + + def test_divide_if_even(self): + self.assertEqual(steps(16), 4) + + def test_even_and_odd_steps(self): + self.assertEqual(steps(12), 9) + + def test_large_number_of_even_and_odd_steps(self): + self.assertEqual(steps(1000000), 152) + + def test_zero_is_an_error(self): + with self.assertRaises(ValueError) as err: + steps(0) + self.assertEqual(type(err.exception), ValueError) + self.assertEqual(err.exception.args[0], "Only positive integers are allowed") + + def test_negative_value_is_an_error(self): + with self.assertRaises(ValueError) as err: + steps(-15) + self.assertEqual(type(err.exception), ValueError) + self.assertEqual(err.exception.args[0], "Only positive integers are allowed") diff --git a/python/currency-exchange/.exercism/config.json b/python/currency-exchange/.exercism/config.json new file mode 100644 index 0000000..a8188cd --- /dev/null +++ b/python/currency-exchange/.exercism/config.json @@ -0,0 +1,28 @@ +{ + "authors": [ + "Ticktakto", + "Yabby1997", + "limm-jk", + "OMEGA-Y", + "wnstj2007", + "J08K" + ], + "contributors": [ + "BethanyG", + "kytrinyx", + "pranasziaukas" + ], + "files": { + "solution": [ + "exchange.py" + ], + "test": [ + "exchange_test.py" + ], + "exemplar": [ + ".meta/exemplar.py" + ] + }, + "icon": "hyperia-forex", + "blurb": "Learn about numbers by solving Chandler's currency exchange conundrums." +} diff --git a/python/currency-exchange/.exercism/metadata.json b/python/currency-exchange/.exercism/metadata.json new file mode 100644 index 0000000..72c9a08 --- /dev/null +++ b/python/currency-exchange/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"currency-exchange","id":"88f9337493ec4da4b29ef8b9633534ab","url":"https://exercism.org/tracks/python/exercises/currency-exchange","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/currency-exchange/HELP.md b/python/currency-exchange/HELP.md new file mode 100644 index 0000000..77f690c --- /dev/null +++ b/python/currency-exchange/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +
+ +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit exchange.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/currency-exchange/HINTS.md b/python/currency-exchange/HINTS.md new file mode 100644 index 0000000..df661c5 --- /dev/null +++ b/python/currency-exchange/HINTS.md @@ -0,0 +1,43 @@ +# Hints + +## General + +- [The Python Numbers Tutorial][python-numbers-tutorial] and [Python numeric types][python-numeric-types] can be a great introduction. + +## 1. Estimate value after exchange + +- You can use the [division operator][division-operator] to get the value of exchanged currency. + +## 2. Calculate currency left after an exchange + +- You can use the [subtraction operator][subtraction-operator] to get the amount of change. + +## 3. Calculate value of bills + +- You can use the [multiplication operator][multiplication-operator] to get the value of bills. + +## 4. Calculate number of bills + +- You need to divide `amount` into `denomination`. +- You need to use type casting to `int` to get the exact number of bills. +- To remove decimal places from a `float`, you can convert it to `int`. + + **Note:** The `//` operator also does floor division. But, if the operand has `float`, the result is still `float`. + +## 5. Calculate leftover after exchanging into bills + +- You need to find the remainder of `amount` that does not equal a whole `denomination`. +- The Modulo operator `%` can help find the remainder. + +## 6. Calculate value after exchange + +- You need to calculate `spread` percent of `exchange_rate` using multiplication operator and add it to `exchange_rate` to get the exchanged currency. +- The actual rate needs to be computed. Remember to add exchange _rate_ and exchange _fee_. +- You can get exchanged money affected by commission by using divide operation and type casting to `int`. + + +[division-operator]: https://docs.python.org/3/tutorial/introduction.html#numbers +[multiplication-operator]: https://docs.python.org/3/tutorial/introduction.html#numbers +[python-numbers-tutorial]: https://docs.python.org/3/tutorial/introduction.html#numbers +[python-numeric-types]: https://docs.python.org/3.9/library/stdtypes.html#numeric-types-int-float-complex +[subtraction-operator]: https://docs.python.org/3/tutorial/introduction.html#numbers \ No newline at end of file diff --git a/python/currency-exchange/README.md b/python/currency-exchange/README.md new file mode 100644 index 0000000..2638f32 --- /dev/null +++ b/python/currency-exchange/README.md @@ -0,0 +1,198 @@ +# Currency Exchange + +Welcome to Currency Exchange on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. +If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :) + +## Introduction + +## Numbers + +There are three different kinds of built-in numbers in Python : `ints`, `floats`, and `complex`. However, in this exercise you'll be dealing only with `ints` and `floats`. + +### ints + +`ints` are whole numbers. e.g. `1234`, `-10`, `20201278`. + +Integers in Python have [arbitrary precision][arbitrary-precision] -- the number of digits is limited only by the available memory of the host system. + +### floats + +`floats` are numbers containing a decimal point. e.g. `0.0`,`3.14`,`-9.01`. + +Floating point numbers are usually implemented in Python using a `double` in C (_15 decimal places of precision_), but will vary in representation based on the host system and other implementation details. This can create some surprises when working with floats, but is "good enough" for most situations. + +You can see more details and discussions in the following resources: + +- [Python numeric type documentation][numeric-type-docs] +- [The Python Tutorial][floating point math] +- [Documentation for `int()` built in][`int()` built in] +- [Documentation for `float()` built in][`float()` built in] +- [0.30000000000000004.com][0.30000000000000004.com] + +## Arithmetic + +Python fully supports arithmetic between `ints` and `floats`. It will convert narrower numbers to match their less narrow counterparts when used with the binary arithmetic operators (`+`, `-`, `*`, `/`, `//`, and `%`). When division with `/`, `//` returns the quotient and `%` returns the remainder. + +Python considers `ints` narrower than `floats`. So, using a float in an expression ensures the result will be a float too. However, when doing division, the result will always be a float, even if only integers are used. + +```python +# The int is widened to a float here, and a float type is returned. +>>> 3 + 4.0 +7.0 +>>> 3 * 4.0 +12.0 +>>> 3 - 2.0 +1.0 +# Division always returns a float. +>>> 6 / 2 +3.0 +>>> 7 / 4 +1.75 +# Calculating remainders. +>>> 7 % 4 +3 +>>> 2 % 4 +2 +>>> 12.75 % 3 +0.75 +``` + +If an int result is needed, you can use `//` to truncate the result. + +```python +>>> 6 // 2 +3 +>>> 7 // 4 +1 +``` + +To convert a float to an integer, you can use `int()`. Also, to convert an integer to a float, you can use `float()`. + +```python +>>> int(6 / 2) +3 +>>> float(1 + 2) +3.0 +``` + +[0.30000000000000004.com]: https://0.30000000000000004.com/ +[`float()` built in]: https://docs.python.org/3/library/functions.html#float +[`int()` built in]: https://docs.python.org/3/library/functions.html#int +[arbitrary-precision]: https://en.wikipedia.org/wiki/Arbitrary-precision_arithmetic#:~:text=In%20computer%20science%2C%20arbitrary%2Dprecision,memory%20of%20the%20host%20system. +[floating point math]: https://docs.python.org/3.9/tutorial/floatingpoint.html +[numeric-type-docs]: https://docs.python.org/3/library/stdtypes.html#typesnumeric + +## Instructions + +Your friend Chandler plans to visit exotic countries all around the world. Sadly, Chandler's math skills aren't good. He's pretty worried about being scammed by currency exchanges during his trip - and he wants you to make a currency calculator for him. Here are his specifications for the app: + +## 1. Estimate value after exchange + +Create the `exchange_money()` function, taking 2 parameters: + +1. `budget` : The amount of money you are planning to exchange. +2. `exchange_rate` : The amount of domestic currency equal to one unit of foreign currency. + +This function should return the value of the exchanged currency. + +**Note:** If your currency is USD and you want to exchange USD for EUR with an exchange rate of `1.20`, then `1.20 USD == 1 EUR`. + +```python +>>> exchange_money(127.5, 1.2) +106.25 +``` + +## 2. Calculate currency left after an exchange + +Create the `get_change()` function, taking 2 parameters: + +1. `budget` : Amount of money before exchange. +2. `exchanging_value` : Amount of money that is *taken* from the budget to be exchanged. + +This function should return the amount of money that *is left* from the budget. + +```python +>>> get_change(127.5, 120) +7.5 +``` + +## 3. Calculate value of bills + +Create the `get_value_of_bills()` function, taking 2 parameters: + +1. `denomination` : The value of a single bill. +2. `number_of_bills` : The total number of bills. + +This exchanging booth only deals in cash of certain increments. +The total you receive must be divisible by the value of one "bill" or unit, which can leave behind a fraction or remainder. +Your function should return only the total value of the bills (_excluding fractional amounts_) the booth would give back. +Unfortunately, the booth gets to keep the remainder/change as an added bonus. + +```python +>>> get_value_of_bills(5, 128) +640 +``` + +## 4. Calculate number of bills + +Create the `get_number_of_bills()` function, taking `amount` and `denomination`. + +This function should return the _number of currency bills_ that you can receive within the given _amount_. +In other words: How many _whole bills_ of currency fit into the starting amount? +Remember -- you can only receive _whole bills_, not fractions of bills, so remember to divide accordingly. +Effectively, you are rounding _down_ to the nearest whole bill/denomination. + +```python +>>> get_number_of_bills(127.5, 5) +25 +``` + +## 5. Calculate leftover after exchanging into bills + +Create the `get_leftover_of_bills()` function, taking `amount` and `denomination`. + +This function should return the _leftover amount_ that cannot be returned from your starting _amount_ given the denomination of bills. +It is very important to know exactly how much the booth gets to keep. + +```python +>>> get_leftover_of_bills(127.5, 20) +7.5 +``` + +## 6. Calculate value after exchange + +Create the `exchangeable_value()` function, taking `budget`, `exchange_rate`, `spread`, and `denomination`. + +Parameter `spread` is the *percentage taken* as an exchange fee, written as an integer. +It needs to be converted to decimal by dividing it by 100. +If `1.00 EUR == 1.20 USD` and the *spread* is `10`, the actual exchange rate will be: `1.00 EUR == 1.32 USD` because 10% of 1.20 is 0.12, and this additional fee is added to the exchange. + +This function should return the maximum value of the new currency after calculating the *exchange rate* plus the *spread*. +Remember that the currency *denomination* is a whole number, and cannot be sub-divided. + +**Note:** Returned value should be `int` type. + +```python +>>> exchangeable_value(127.25, 1.20, 10, 20) +80 +>>> exchangeable_value(127.25, 1.20, 10, 5) +95 +``` + +## Source + +### Created by + +- @Ticktakto +- @Yabby1997 +- @limm-jk +- @OMEGA-Y +- @wnstj2007 +- @J08K + +### Contributed to by + +- @BethanyG +- @kytrinyx +- @pranasziaukas \ No newline at end of file diff --git a/python/currency-exchange/__pycache__/exchange.cpython-313.pyc b/python/currency-exchange/__pycache__/exchange.cpython-313.pyc new file mode 100644 index 0000000..5f93698 Binary files /dev/null and b/python/currency-exchange/__pycache__/exchange.cpython-313.pyc differ diff --git a/python/currency-exchange/__pycache__/exchange.cpython-314.pyc b/python/currency-exchange/__pycache__/exchange.cpython-314.pyc new file mode 100644 index 0000000..04de78d Binary files /dev/null and b/python/currency-exchange/__pycache__/exchange.cpython-314.pyc differ diff --git a/python/currency-exchange/__pycache__/exchange_test.cpython-313-pytest-8.3.4.pyc b/python/currency-exchange/__pycache__/exchange_test.cpython-313-pytest-8.3.4.pyc new file mode 100644 index 0000000..2cd7f15 Binary files /dev/null and b/python/currency-exchange/__pycache__/exchange_test.cpython-313-pytest-8.3.4.pyc differ diff --git a/python/currency-exchange/__pycache__/exchange_test.cpython-314-pytest-9.1.0.pyc b/python/currency-exchange/__pycache__/exchange_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..7dcbcbb Binary files /dev/null and b/python/currency-exchange/__pycache__/exchange_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/currency-exchange/exchange.py b/python/currency-exchange/exchange.py new file mode 100644 index 0000000..988169a --- /dev/null +++ b/python/currency-exchange/exchange.py @@ -0,0 +1,70 @@ +"""Functions for calculating steps in exchanging currency. + +Python numbers documentation: https://docs.python.org/3/library/stdtypes.html#numeric-types-int-float-complex + +Overview of exchanging currency when travelling: https://www.compareremit.com/money-transfer-tips/guide-to-exchanging-currency-for-overseas-travel/ +""" + + +def exchange_money(budget, exchange_rate): + """ + + :param budget: float - amount of money you are planning to exchange. + :param exchange_rate: float - unit value of the foreign currency. + :return: float - exchanged value of the foreign currency you can receive. + """ + return budget / exchange_rate + + +def get_change(budget, exchanging_value): + """ + + :param budget: float - amount of money you own. + :param exchanging_value: float - amount of your money you want to exchange now. + :return: float - amount left of your starting currency after exchanging. + """ + return budget - exchanging_value + + +def get_value_of_bills(denomination, number_of_bills): + """ + + :param denomination: int - the value of a bill. + :param number_of_bills: int - total number of bills. + :return: int - calculated value of the bills. + """ + return denomination * number_of_bills + + +def get_number_of_bills(amount, denomination): + """ + + :param amount: float - the total starting value. + :param denomination: int - the value of a single bill. + :return: int - number of bills that can be obtained from the amount. + """ + return amount // denomination + + +def get_leftover_of_bills(amount, denomination): + """ + + :param amount: float - the total starting value. + :param denomination: int - the value of a single bill. + :return: float - the amount that is "leftover", given the current denomination. + """ + return amount % denomination + + +def exchangeable_value(budget, exchange_rate, spread, denomination): + """ + + :param budget: float - the amount of your money you are planning to exchange. + :param exchange_rate: float - the unit value of the foreign currency. + :param spread: int - percentage that is taken as an exchange fee. + :param denomination: int - the value of a single bill. + :return: int - maximum value you can get. + """ + exchange_rate_with_spread = exchange_rate * (1 + (spread / 100)) + max_amount_to_exhange = exchange_money(budget, exchange_rate_with_spread) + return denomination * get_number_of_bills(max_amount_to_exhange, denomination) diff --git a/python/currency-exchange/exchange_test.py b/python/currency-exchange/exchange_test.py new file mode 100644 index 0000000..fd3754c --- /dev/null +++ b/python/currency-exchange/exchange_test.py @@ -0,0 +1,141 @@ +import unittest +import pytest + +from exchange import ( + exchange_money, + get_change, + get_value_of_bills, + get_number_of_bills, + get_leftover_of_bills, + exchangeable_value) + + +class CurrencyExchangeTest(unittest.TestCase): + @pytest.mark.task(taskno=1) + def test_exchange_money(self): + test_data = [(100000, 0.8), (700000, 10.0)] + result_data = [125000, 70000] + + for variant, (params, expected) in enumerate(zip(test_data, result_data), start=1): + budget, exchange_rate = params + + with self.subTest(f"variation #{variant}", + budget=budget, + exchange_rate=exchange_rate, + expected=expected): + + actual_result = exchange_money(*params) + error_message = (f'Called exchange_money{budget, exchange_rate}. ' + f'The function returned {actual_result}, but ' + f'The tests expected {expected} when exchanging' + f' {budget} at a rate of {exchange_rate}.') + + self.assertAlmostEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=2) + def test_get_change(self): + test_data = [(463000, 5000), (1250, 120), (15000, 1380)] + result_data = [458000, 1130, 13620] + + for variant, (params, expected) in enumerate(zip(test_data, result_data), start=1): + budget, exchanging_value = params + + with self.subTest(f"variation #{variant}", + budget=budget, + exchanging_value=exchanging_value, + expected=expected): + + actual_result = get_change(*params) + error_message = (f'Called get_change{budget, exchanging_value}. ' + f'The function returned {actual_result}, but ' + f'The tests expected {expected} left in your budget.') + + self.assertAlmostEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=3) + def test_get_value_of_bills(self): + test_data = [(10000, 128), (50, 360), (200, 200)] + result_data = [1280000, 18000, 40000] + + for variant, (params, expected) in enumerate(zip(test_data, result_data), start=1): + denomination, number_of_bills = params + + with self.subTest(f"variation #{variant}", + denomination=denomination, + number_of_bills=number_of_bills, + expected=expected): + + actual_result = get_value_of_bills(*params) + error_message = (f'Called get_value_of_bills{denomination, number_of_bills}. ' + f'The function returned {actual_result}, but ' + f'The tests expected {expected} for the bills value.') + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=4) + def test_get_number_of_bills(self): + test_data = [(163270, 50000), (54361, 1000)] + result_data = [3, 54] + + for variant, (params, expected) in enumerate(zip(test_data, result_data), start=1): + amount, denomination = params + + with self.subTest(f"variation #{variant}", + amount=amount, + denomination=denomination, + expected=expected): + + actual_result = get_number_of_bills(amount, denomination) + error_message = (f'Called get_number_of_bills{amount, denomination}. ' + f'The function returned {actual_result} bills, but ' + f'The tests expected {expected} bills.') + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=5) + def test_get_leftover_of_bills(self): + test_data = [(10.1, 10), (654321.0, 5), (3.14, 2)] + result_data = [0.1, 1.0, 1.14] + + for variant, (params, expected) in enumerate(zip(test_data, result_data), start=1): + amount, denomination = params + + with self.subTest(f"variation #{variant}", + amount=amount, + denomination=denomination, + expected=expected): + + actual_result = get_leftover_of_bills(*params) + error_message = (f'Called get_leftover_of_bills{amount, denomination}. ' + f'The function returned {actual_result}, but ' + f'The tests expected {expected} as the leftover amount.') + + self.assertAlmostEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=6) + def test_exchangeable_value(self): + test_data = [(100000, 10.61, 10, 1), + (1500, 0.84, 25, 40), + (470000, 1050, 30, 10000000000), + (470000, 0.00000009, 30, 700), + (425.33, 0.0009, 30, 700)] + + result_data = [8568, 1400, 0, 4017094016600, 363300] + + for variant, (params, expected) in enumerate(zip(test_data, result_data), start=1): + budget, exchange_rate, spread, denomination = params + + with self.subTest(f"variation #{variant}", + budget=budget, + exchange_rate=exchange_rate, + spread=spread, + denomination=denomination, + expected=expected): + + actual_result = exchangeable_value(budget, exchange_rate, spread, denomination) + error_message = (f'Called exchangeable_value{budget, exchange_rate, spread, denomination}. ' + f'The function returned {actual_result}, but ' + f'The tests expected {expected} as the maximum ' + f'value of the new currency .') + + self.assertEqual(actual_result, expected, msg=error_message) diff --git a/python/darts/.exercism/config.json b/python/darts/.exercism/config.json new file mode 100644 index 0000000..cc71df1 --- /dev/null +++ b/python/darts/.exercism/config.json @@ -0,0 +1,29 @@ +{ + "authors": [ + "GascaK" + ], + "contributors": [ + "alexpjohnson", + "AnAccountForReportingBugs", + "BethanyG", + "cmccandless", + "Dog", + "Grociu", + "tqa236", + "xitanggg", + "yawpitch" + ], + "files": { + "solution": [ + "darts.py" + ], + "test": [ + "darts_test.py" + ], + "example": [ + ".meta/example.py" + ] + }, + "blurb": "Calculate the points scored in a single toss of a Darts game.", + "source": "Inspired by an exercise created by a professor Della Paolera in Argentina" +} diff --git a/python/darts/.exercism/metadata.json b/python/darts/.exercism/metadata.json new file mode 100644 index 0000000..0ce0877 --- /dev/null +++ b/python/darts/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"darts","id":"984db0dd20f04821b2e61a29c8343227","url":"https://exercism.org/tracks/python/exercises/darts","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/darts/HELP.md b/python/darts/HELP.md new file mode 100644 index 0000000..2c3b282 --- /dev/null +++ b/python/darts/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +
+ +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit darts.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/darts/HINTS.md b/python/darts/HINTS.md new file mode 100644 index 0000000..a2b48d2 --- /dev/null +++ b/python/darts/HINTS.md @@ -0,0 +1,20 @@ +# Hints + +## General + +- This challenge is all about calculating if a point falls _on, in, or outside_ a given circle. +- There are two different ways of calculating if a point falls on, in, or outside a circle. + - This _Stack Overflow_ Post: [Equation for Testing if a Point is Inside a Circle][point-circle-equation] outlines one method. + - This _DoubleRoot_ post [Position of a point relative to a circle][point-to-circle] outlines a different one. + - This _Math is Fun_ post covers a more general [Distance Between 2 Points][distance-between-two-points] calculation. +- Because the dart board is a set of _concentric_ circles, the order in which you calculate points could change the answer significantly. + You should pay attention to which direction your calculations "move" in. +- Remember that this exercise has many potential solutions and many paths you can take along the way. + No path is manifestly "better" than another, although a particular path may be more interesting or better suited to what you want to learn or explore right now. +- Some paths may trade speed for clarity. + Others might take up more memory but be more scalable or maintainable. +- We encourage you to try out more than one programming strategy to see what happens. + +[point-circle-equation]: https://stackoverflow.com/questions/481144/equation-for-testing-if-a-point-is-inside-a-circle +[point-to-circle]: https://doubleroot.in/lessons/circle/position-of-a-point/ +[distance-between-two-points]: https://www.mathsisfun.com/algebra/distance-2-points.html \ No newline at end of file diff --git a/python/darts/README.md b/python/darts/README.md new file mode 100644 index 0000000..4119b79 --- /dev/null +++ b/python/darts/README.md @@ -0,0 +1,59 @@ +# Darts + +Welcome to Darts on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. +If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :) + +## Instructions + +Calculate the points scored in a single toss of a Darts game. + +[Darts][darts] is a game where players throw darts at a [target][darts-target]. + +In our particular instance of the game, the target rewards 4 different amounts of points, depending on where the dart lands: + +![Our dart scoreboard with values from a complete miss to a bullseye](https://assets.exercism.org/images/exercises/darts/darts-scoreboard.svg) + +- If the dart lands outside the target, player earns no points (0 points). +- If the dart lands in the outer circle of the target, player earns 1 point. +- If the dart lands in the middle circle of the target, player earns 5 points. +- If the dart lands in the inner circle of the target, player earns 10 points. + +The outer circle has a radius of 10 units (this is equivalent to the total radius for the entire target), the middle circle a radius of 5 units, and the inner circle a radius of 1. +Of course, they are all centered at the same point — that is, the circles are [concentric][] defined by the coordinates (0, 0). + +Given a point in the target (defined by its [Cartesian coordinates][cartesian-coordinates] `x` and `y`, where `x` and `y` are [real][real-numbers]), calculate the correct score earned by a dart landing at that point. + +## Credit + +The scoreboard image was created by [habere-et-dispertire][habere-et-dispertire] using [Inkscape][inkscape]. + +[darts]: https://en.wikipedia.org/wiki/Darts +[darts-target]: https://en.wikipedia.org/wiki/Darts#/media/File:Darts_in_a_dartboard.jpg +[concentric]: https://mathworld.wolfram.com/ConcentricCircles.html +[cartesian-coordinates]: https://www.mathsisfun.com/data/cartesian-coordinates.html +[real-numbers]: https://www.mathsisfun.com/numbers/real-numbers.html +[habere-et-dispertire]: https://exercism.org/profiles/habere-et-dispertire +[inkscape]: https://en.wikipedia.org/wiki/Inkscape + +## Source + +### Created by + +- @GascaK + +### Contributed to by + +- @alexpjohnson +- @AnAccountForReportingBugs +- @BethanyG +- @cmccandless +- @Dog +- @Grociu +- @tqa236 +- @xitanggg +- @yawpitch + +### Based on + +Inspired by an exercise created by a professor Della Paolera in Argentina \ No newline at end of file diff --git a/python/darts/__pycache__/darts.cpython-313.pyc b/python/darts/__pycache__/darts.cpython-313.pyc new file mode 100644 index 0000000..02d90b8 Binary files /dev/null and b/python/darts/__pycache__/darts.cpython-313.pyc differ diff --git a/python/darts/__pycache__/darts.cpython-314.pyc b/python/darts/__pycache__/darts.cpython-314.pyc new file mode 100644 index 0000000..5876ba5 Binary files /dev/null and b/python/darts/__pycache__/darts.cpython-314.pyc differ diff --git a/python/darts/__pycache__/darts_test.cpython-313-pytest-8.3.4.pyc b/python/darts/__pycache__/darts_test.cpython-313-pytest-8.3.4.pyc new file mode 100644 index 0000000..8a7a372 Binary files /dev/null and b/python/darts/__pycache__/darts_test.cpython-313-pytest-8.3.4.pyc differ diff --git a/python/darts/__pycache__/darts_test.cpython-314-pytest-9.1.0.pyc b/python/darts/__pycache__/darts_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..b6040f9 Binary files /dev/null and b/python/darts/__pycache__/darts_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/darts/darts.py b/python/darts/darts.py new file mode 100644 index 0000000..9f146ab --- /dev/null +++ b/python/darts/darts.py @@ -0,0 +1,13 @@ +from math import sqrt + + +def score(x, y): + distance_to_center: float = sqrt(x**2 + y**2) + if distance_to_center <= 1.0: + return 10 + elif distance_to_center <= 5.0: + return 5 + elif distance_to_center <= 10.0: + return 1 + else: + return 0 diff --git a/python/darts/darts_test.py b/python/darts/darts_test.py new file mode 100644 index 0000000..5e16704 --- /dev/null +++ b/python/darts/darts_test.py @@ -0,0 +1,50 @@ +# These tests are auto-generated with test data from: +# https://github.com/exercism/problem-specifications/tree/main/exercises/darts/canonical-data.json +# File last updated on 2023-07-19 + +import unittest + +from darts import ( + score, +) + + +class DartsTest(unittest.TestCase): + def test_missed_target(self): + self.assertEqual(score(-9, 9), 0) + + def test_on_the_outer_circle(self): + self.assertEqual(score(0, 10), 1) + + def test_on_the_middle_circle(self): + self.assertEqual(score(-5, 0), 5) + + def test_on_the_inner_circle(self): + self.assertEqual(score(0, -1), 10) + + def test_exactly_on_center(self): + self.assertEqual(score(0, 0), 10) + + def test_near_the_center(self): + self.assertEqual(score(-0.1, -0.1), 10) + + def test_just_within_the_inner_circle(self): + self.assertEqual(score(0.7, 0.7), 10) + + def test_just_outside_the_inner_circle(self): + self.assertEqual(score(0.8, -0.8), 5) + + def test_just_within_the_middle_circle(self): + self.assertEqual(score(-3.5, 3.5), 5) + + def test_just_outside_the_middle_circle(self): + self.assertEqual(score(-3.6, -3.6), 1) + + def test_just_within_the_outer_circle(self): + self.assertEqual(score(-7.0, 7.0), 1) + + def test_just_outside_the_outer_circle(self): + self.assertEqual(score(7.1, -7.1), 0) + + def test_asymmetric_position_between_the_inner_and_middle_circles(self): + self.assertEqual(score(0.5, -4), 5) diff --git a/python/diamond/.exercism/config.json b/python/diamond/.exercism/config.json new file mode 100644 index 0000000..f349d65 --- /dev/null +++ b/python/diamond/.exercism/config.json @@ -0,0 +1,30 @@ +{ + "authors": [ + "behrtam" + ], + "contributors": [ + "BethanyG", + "cmccandless", + "Dog", + "ikhadykin", + "lucasdpau", + "N-Parsons", + "pheanex", + "rjsabatini", + "tqa236" + ], + "files": { + "solution": [ + "diamond.py" + ], + "test": [ + "diamond_test.py" + ], + "example": [ + ".meta/example.py" + ] + }, + "blurb": "Given a letter, print a diamond starting with 'A' with the supplied letter at the widest point.", + "source": "Seb Rose", + "source_url": "https://web.archive.org/web/20220807163751/http://claysnow.co.uk/recycling-tests-in-tdd/" +} diff --git a/python/diamond/.exercism/metadata.json b/python/diamond/.exercism/metadata.json new file mode 100644 index 0000000..420f58b --- /dev/null +++ b/python/diamond/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"diamond","id":"00b66dccae6a416da54bab3dd7c63036","url":"https://exercism.org/tracks/python/exercises/diamond","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/diamond/HELP.md b/python/diamond/HELP.md new file mode 100644 index 0000000..b4d1c8e --- /dev/null +++ b/python/diamond/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd +``` + +Windows +```powershell +PS C:\Users\foobar> cd +``` + +
+ +Next, run the `pytest` command in your terminal, replacing `` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit diamond.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [Python Community Forums](https://discuss.python.org/) help, PEP discussion, core Python committers, and more. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [The Exercism Community Discussion Forums](https://forum.exercsim.org) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/diamond/README.md b/python/diamond/README.md new file mode 100644 index 0000000..8b47985 --- /dev/null +++ b/python/diamond/README.md @@ -0,0 +1,79 @@ +# Diamond + +Welcome to Diamond on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Instructions + +The diamond kata takes as its input a letter, and outputs it in a diamond shape. +Given a letter, it prints a diamond starting with 'A', with the supplied letter at the widest point. + +## Requirements + +- The first row contains one 'A'. +- The last row contains one 'A'. +- All rows, except the first and last, have exactly two identical letters. +- All rows have as many trailing spaces as leading spaces. (This might be 0). +- The diamond is horizontally symmetric. +- The diamond is vertically symmetric. +- The diamond has a square shape (width equals height). +- The letters form a diamond shape. +- The top half has the letters in ascending order. +- The bottom half has the letters in descending order. +- The four corners (containing the spaces) are triangles. + +## Examples + +In the following examples, spaces are indicated by `·` characters. + +Diamond for letter 'A': + +```text +A +``` + +Diamond for letter 'C': + +```text +··A·· +·B·B· +C···C +·B·B· +··A·· +``` + +Diamond for letter 'E': + +```text +····A···· +···B·B··· +··C···C·· +·D·····D· +E·······E +·D·····D· +··C···C·· +···B·B··· +····A···· +``` + +## Source + +### Created by + +- @behrtam + +### Contributed to by + +- @BethanyG +- @cmccandless +- @Dog +- @ikhadykin +- @lucasdpau +- @N-Parsons +- @pheanex +- @rjsabatini +- @tqa236 + +### Based on + +Seb Rose - https://web.archive.org/web/20220807163751/http://claysnow.co.uk/recycling-tests-in-tdd/ \ No newline at end of file diff --git a/python/diamond/__pycache__/diamond.cpython-314.pyc b/python/diamond/__pycache__/diamond.cpython-314.pyc new file mode 100644 index 0000000..fc9fc25 Binary files /dev/null and b/python/diamond/__pycache__/diamond.cpython-314.pyc differ diff --git a/python/diamond/__pycache__/diamond_test.cpython-314-pytest-9.1.0.pyc b/python/diamond/__pycache__/diamond_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..cabe3b2 Binary files /dev/null and b/python/diamond/__pycache__/diamond_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/diamond/diamond.py b/python/diamond/diamond.py new file mode 100644 index 0000000..568df31 --- /dev/null +++ b/python/diamond/diamond.py @@ -0,0 +1,24 @@ +def rows(letter): + diamond: list[str] = [] + for current_letter in range(ord("A"), ord(letter) + 1): + outter_lenght: int = ord(letter) - current_letter + inner_lenght: int = (((ord(letter) - ord("A")) * 2) - 1) - (outter_lenght * 2) + outter_spaces: str = outter_lenght * " " + inner_spaces: str = inner_lenght * " " + new_row: str = "" + if current_letter == ord("A"): + new_row = ( + (ord(letter) - ord("A")) * " " + "A" + (ord(letter) - ord("A")) * " " + ) + else: + new_row = ( + outter_spaces + + chr(current_letter) + + inner_spaces + + chr(current_letter) + + outter_spaces + ) + diamond.append(new_row) + for row in range(len(diamond) - 2, -1, -1): + diamond.append(diamond[row]) + return diamond diff --git a/python/diamond/diamond_test.py b/python/diamond/diamond_test.py new file mode 100644 index 0000000..448f65d --- /dev/null +++ b/python/diamond/diamond_test.py @@ -0,0 +1,92 @@ +# These tests are auto-generated with test data from: +# https://github.com/exercism/problem-specifications/tree/main/exercises/diamond/canonical-data.json +# File last updated on 2026-02-19 + +import unittest + +from diamond import ( + rows, +) + + +class DiamondTest(unittest.TestCase): + + def test_degenerate_case_with_a_single_a_row(self): + result = ["A"] + self.assertEqual(rows("A"), result) + + def test_degenerate_case_with_no_row_containing_3_distinct_groups_of_spaces(self): + result = [" A ", "B B", " A "] + self.assertEqual(rows("B"), result) + + def test_smallest_non_degenerate_case_with_odd_diamond_side_length(self): + result = [" A ", " B B ", "C C", " B B ", " A "] + self.assertEqual(rows("C"), result) + + def test_smallest_non_degenerate_case_with_even_diamond_side_length(self): + result = [ + " A ", + " B B ", + " C C ", + "D D", + " C C ", + " B B ", + " A ", + ] + self.assertEqual(rows("D"), result) + + def test_largest_possible_diamond(self): + result = [ + " A ", + " B B ", + " C C ", + " D D ", + " E E ", + " F F ", + " G G ", + " H H ", + " I I ", + " J J ", + " K K ", + " L L ", + " M M ", + " N N ", + " O O ", + " P P ", + " Q Q ", + " R R ", + " S S ", + " T T ", + " U U ", + " V V ", + " W W ", + " X X ", + " Y Y ", + "Z Z", + " Y Y ", + " X X ", + " W W ", + " V V ", + " U U ", + " T T ", + " S S ", + " R R ", + " Q Q ", + " P P ", + " O O ", + " N N ", + " M M ", + " L L ", + " K K ", + " J J ", + " I I ", + " H H ", + " G G ", + " F F ", + " E E ", + " D D ", + " C C ", + " B B ", + " A ", + ] + self.assertEqual(rows("Z"), result) diff --git a/python/difference-of-squares/.exercism/config.json b/python/difference-of-squares/.exercism/config.json new file mode 100644 index 0000000..fe714d4 --- /dev/null +++ b/python/difference-of-squares/.exercism/config.json @@ -0,0 +1,32 @@ +{ + "authors": [ + "sjakobi" + ], + "contributors": [ + "akashsara", + "behrtam", + "BethanyG", + "cmccandless", + "Dog", + "ikhadykin", + "kytrinyx", + "N-Parsons", + "pheanex", + "tqa236", + "yawpitch" + ], + "files": { + "solution": [ + "difference_of_squares.py" + ], + "test": [ + "difference_of_squares_test.py" + ], + "example": [ + ".meta/example.py" + ] + }, + "blurb": "Find the difference between the square of the sum and the sum of the squares of the first N natural numbers.", + "source": "Problem 6 at Project Euler", + "source_url": "https://projecteuler.net/problem=6" +} diff --git a/python/difference-of-squares/.exercism/metadata.json b/python/difference-of-squares/.exercism/metadata.json new file mode 100644 index 0000000..12820f9 --- /dev/null +++ b/python/difference-of-squares/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"difference-of-squares","id":"e17a9483ce9b4983852101551cde075a","url":"https://exercism.org/tracks/python/exercises/difference-of-squares","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/difference-of-squares/HELP.md b/python/difference-of-squares/HELP.md new file mode 100644 index 0000000..2ea0735 --- /dev/null +++ b/python/difference-of-squares/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +
+ +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit difference_of_squares.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/difference-of-squares/README.md b/python/difference-of-squares/README.md new file mode 100644 index 0000000..90c4169 --- /dev/null +++ b/python/difference-of-squares/README.md @@ -0,0 +1,43 @@ +# Difference of Squares + +Welcome to Difference of Squares on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Instructions + +Find the difference between the square of the sum and the sum of the squares of the first N natural numbers. + +The square of the sum of the first ten natural numbers is +(1 + 2 + ... + 10)² = 55² = 3025. + +The sum of the squares of the first ten natural numbers is +1² + 2² + ... + 10² = 385. + +Hence the difference between the square of the sum of the first ten natural numbers and the sum of the squares of the first ten natural numbers is 3025 - 385 = 2640. + +You are not expected to discover an efficient solution to this yourself from first principles; research is allowed, indeed, encouraged. +Finding the best algorithm for the problem is a key skill in software engineering. + +## Source + +### Created by + +- @sjakobi + +### Contributed to by + +- @akashsara +- @behrtam +- @BethanyG +- @cmccandless +- @Dog +- @ikhadykin +- @kytrinyx +- @N-Parsons +- @pheanex +- @tqa236 +- @yawpitch + +### Based on + +Problem 6 at Project Euler - https://projecteuler.net/problem=6 \ No newline at end of file diff --git a/python/difference-of-squares/__pycache__/difference_of_squares.cpython-313.pyc b/python/difference-of-squares/__pycache__/difference_of_squares.cpython-313.pyc new file mode 100644 index 0000000..461618f Binary files /dev/null and b/python/difference-of-squares/__pycache__/difference_of_squares.cpython-313.pyc differ diff --git a/python/difference-of-squares/__pycache__/difference_of_squares.cpython-314.pyc b/python/difference-of-squares/__pycache__/difference_of_squares.cpython-314.pyc new file mode 100644 index 0000000..c8a0371 Binary files /dev/null and b/python/difference-of-squares/__pycache__/difference_of_squares.cpython-314.pyc differ diff --git a/python/difference-of-squares/__pycache__/difference_of_squares_test.cpython-313-pytest-8.3.5.pyc b/python/difference-of-squares/__pycache__/difference_of_squares_test.cpython-313-pytest-8.3.5.pyc new file mode 100644 index 0000000..dbcbb9d Binary files /dev/null and b/python/difference-of-squares/__pycache__/difference_of_squares_test.cpython-313-pytest-8.3.5.pyc differ diff --git a/python/difference-of-squares/__pycache__/difference_of_squares_test.cpython-314-pytest-9.1.0.pyc b/python/difference-of-squares/__pycache__/difference_of_squares_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..f4284f2 Binary files /dev/null and b/python/difference-of-squares/__pycache__/difference_of_squares_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/difference-of-squares/difference_of_squares.py b/python/difference-of-squares/difference_of_squares.py new file mode 100644 index 0000000..ce16a60 --- /dev/null +++ b/python/difference-of-squares/difference_of_squares.py @@ -0,0 +1,16 @@ +def square_of_sum(number: int) -> int: + sum: int = 0 + for integer in range(1, number + 1): + sum += integer + return sum**2 + + +def sum_of_squares(number: int) -> int: + sum: int = 0 + for integer in range(1, number + 1): + sum += integer**2 + return sum + + +def difference_of_squares(number: int) -> int: + return square_of_sum(number) - sum_of_squares(number) diff --git a/python/difference-of-squares/difference_of_squares_test.py b/python/difference-of-squares/difference_of_squares_test.py new file mode 100644 index 0000000..aa72719 --- /dev/null +++ b/python/difference-of-squares/difference_of_squares_test.py @@ -0,0 +1,40 @@ +# These tests are auto-generated with test data from: +# https://github.com/exercism/problem-specifications/tree/main/exercises/difference-of-squares/canonical-data.json +# File last updated on 2023-07-19 + +import unittest + +from difference_of_squares import ( + difference_of_squares, + square_of_sum, + sum_of_squares, +) + + +class DifferenceOfSquaresTest(unittest.TestCase): + def test_square_of_sum_1(self): + self.assertEqual(square_of_sum(1), 1) + + def test_square_of_sum_5(self): + self.assertEqual(square_of_sum(5), 225) + + def test_square_of_sum_100(self): + self.assertEqual(square_of_sum(100), 25502500) + + def test_sum_of_squares_1(self): + self.assertEqual(sum_of_squares(1), 1) + + def test_sum_of_squares_5(self): + self.assertEqual(sum_of_squares(5), 55) + + def test_sum_of_squares_100(self): + self.assertEqual(sum_of_squares(100), 338350) + + def test_difference_of_squares_1(self): + self.assertEqual(difference_of_squares(1), 0) + + def test_difference_of_squares_5(self): + self.assertEqual(difference_of_squares(5), 170) + + def test_difference_of_squares_100(self): + self.assertEqual(difference_of_squares(100), 25164150) diff --git a/python/eliuds-eggs/.exercism/config.json b/python/eliuds-eggs/.exercism/config.json new file mode 100644 index 0000000..a230751 --- /dev/null +++ b/python/eliuds-eggs/.exercism/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "vaeng" + ], + "files": { + "solution": [ + "eliuds_eggs.py" + ], + "test": [ + "eliuds_eggs_test.py" + ], + "example": [ + ".meta/example.py" + ] + }, + "blurb": "Help Eliud count the number of eggs in her chicken coop by counting the number of 1 bits in a binary representation.", + "source": "Christian Willner, Eric Willigers", + "source_url": "https://forum.exercism.org/t/new-exercise-suggestion-pop-count/7632/5" +} diff --git a/python/eliuds-eggs/.exercism/metadata.json b/python/eliuds-eggs/.exercism/metadata.json new file mode 100644 index 0000000..d59900c --- /dev/null +++ b/python/eliuds-eggs/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"eliuds-eggs","id":"73903ca7efa846688f019068426e4f5d","url":"https://exercism.org/tracks/python/exercises/eliuds-eggs","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/eliuds-eggs/HELP.md b/python/eliuds-eggs/HELP.md new file mode 100644 index 0000000..28faabb --- /dev/null +++ b/python/eliuds-eggs/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Correr os testes + +Usamos o [pytest][pytest: Getting Started Guide] como executor de testes do nosso site. +Vais precisar de instalar o `pytest` na tua máquina de desenvolvimento se quiseres correr os testes do percurso Python localmente. +Também vais precisar de instalar os seguintes plugins do `pytest`: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Encontras informação mais detalhada no [guia de testes de Python][Python track tests page] do nosso site. + + +### Correr os testes + +Para correres os testes incluídos, navega até à pasta onde o exercício está guardado usando o `cd` no teu terminal (_substitui `` abaixo pelo teu caminho_). +Os ficheiros de teste terminam habitualmente em `_test.py` e são os mesmos testes que correm no site quando uma solução é submetida. + +Linux/MacOS +```bash +$ cd +``` + +Windows +```powershell +PS C:\Users\foobar> cd +``` + +
+ +De seguida, corre o comando `pytest` no teu terminal, substituindo `` pelo nome do ficheiro de teste: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task +==================== 7 passed in 0.08s ==================== +``` + + +### Opções comuns +- `-o` : substitui o `pytest.ini` predefinido (_podes usar esta opção para evitar avisos de marcadores_) +- `-v` : ativa a saída detalhada. +- `-x` : para de correr os testes na primeira falha. +- `--ff` : corre as falhas do teste anterior antes de correr os outros casos de teste. + +Para opções adicionais, usa `python3 -m pytest -h` ou `py -m pytest -h`. + + +### Corrigir avisos + +Se não usares `pytest -o markers=task` ao invocar o `pytest`, podes receber um `PytestUnknownMarkWarning` nos testes que usam a nossa nova sintaxe: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +Para evitares escrever `pytest -o markers=task` em todos os testes que corres, podes usar um ficheiro de configuração `pytest.ini`. +Criámos um que podes descarregar a partir do nível de topo do diretório do percurso Python: [pytest.ini][pytest.ini]. + +Também podes criar o teu próprio ficheiro `pytest.ini` com o seguinte conteúdo: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Colocar o ficheiro `pytest.ini` no diretório _root_ ou _working_ dos teus exercícios do percurso Python regista os marcadores e faz parar os avisos. +Encontras mais informação sobre os marcadores do pytest na documentação do `pytest` sobre [marcar funções de teste][pytest: marking test functions with attributes] e na documentação do `pytest` sobre [trabalhar com marcadores personalizados][pytest: working with custom markers]. + +Encontras informação sobre como personalizar as configurações do pytest na documentação do `pytest` sobre [formatos de ficheiros de configuração][pytest: configuration file formats]. + + +### Estender o teu IDE ou editor de código + +Muitos IDEs e editores de código têm suporte integrado para usar o `pytest` e outras ferramentas de qualidade de código. +Podes encontrar algumas opções da comunidade na nossa [página de ferramentas do percurso Python][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submeter a tua solução + +Podes submeter a tua solução com o comando `exercism submit eliuds_eggs.py`. +Este comando envia a tua solução para o site do Exercism e imprime o URL da página da solução. + +É possível submeter uma solução incompleta, o que te permite: + +- Ver como outras pessoas resolveram o exercício +- Pedir ajuda a um mentor + +## Precisas de ajuda? + +Se quiseres ajuda para resolver o exercício, consulta as seguintes páginas: + +- A [documentação do percurso Python](https://exercism.org/docs/tracks/python) +- A [categoria de programação do percurso Python no fórum](https://forum.exercism.org/c/programming/python) +- A [categoria de programação do Exercism no fórum](https://forum.exercism.org/c/programming/5) +- As [Perguntas Frequentes](https://exercism.org/docs/using/faqs) + +Se esses recursos não forem suficientes, podes submeter a tua solução (incompleta) para pedir mentoria. + +Abaixo encontras alguns recursos para obter ajuda, caso tenhas problemas: + +- [A PSF](https://www.python.org) aloja as transferências do Python, a documentação e recursos da comunidade. +- Os [Fóruns da Comunidade Python](https://discuss.python.org/) servem para obter ajuda, discutir PEPs, falar com os principais contribuidores do Python e muito mais. +- [A Comunidade do Exercism no Discord](https://exercism.org/r/discord) +- [Os Fóruns de Discussão da Comunidade do Exercism](https://forum.exercsim.org) +- A [Comunidade Python no Discord](https://pythondiscord.com/) é uma comunidade muito prestável e ativa. +- O [/r/learnpython/](https://www.reddit.com/r/learnpython/) é um subreddit pensado para quem está a aprender Python. +- O [#python no Libera.chat](https://www.python.org/community/irc/) é o sítio onde os programadores responsáveis pela linguagem se juntam e põem o trabalho em dia. +- Os [Fóruns da Comunidade Free Code Camp](https://forum.freecodecamp.org/) +- O [Pythontutor](http://pythontutor.com/) para percorrer pequenos excertos de código visualmente. + +Além disso, o [StackOverflow](http://stackoverflow.com/questions/tagged/python) é um bom sítio para procurar o teu problema ou a tua dúvida e ver se já foi respondida. +Se não foi, podes sempre [perguntar](https://stackoverflow.com/help/how-to-ask) ou [responder](https://stackoverflow.com/help/how-to-answer) à pergunta de outra pessoa. \ No newline at end of file diff --git a/python/eliuds-eggs/README.md b/python/eliuds-eggs/README.md new file mode 100644 index 0000000..9752e91 --- /dev/null +++ b/python/eliuds-eggs/README.md @@ -0,0 +1,89 @@ +# Os Ovos de Eliud + +Bem-vindo ao Os Ovos de Eliud no percurso Python do Exercism. +Se precisares de ajuda para correr os testes ou para submeter o teu código, consulta o `HELP.md`. + +## Introduction + +A tua amiga Eliud herdou uma quinta da avó, a Tigist. +A avó era inventora e tinha tendência para construir as coisas de forma demasiado complicada. +O galinheiro tem um ecrã digital que mostra um número codificado, o qual representa as posições de todos os ovos que podem ser recolhidos. + +A Eliud pede-te para escreveres um programa que mostre o número real de ovos no galinheiro. + +A codificação da informação das posições calcula-se da seguinte forma: + +1. Percorre os possíveis locais de postura e assinala com `1` os que têm um ovo e com `0` os que estão vazios. +2. Converte o número de binário para decimal. +3. Mostra o resultado no ecrã. + +## Exemplo 1 + +![Sete ninhos individuais dispostos numa fila, em que o primeiro, o terceiro, o quarto e o sétimo têm cada um um único ovo.](https://assets.exercism.org/images/exercises/eliuds-eggs/example-1-coop.svg) + +```text + _ _ _ _ _ _ _ +|E| |E|E| | |E| +``` + +### Binário resultante + +![1011001](https://assets.exercism.org/images/exercises/eliuds-eggs/example-1-binary.svg) + +```text + _ _ _ _ _ _ _ +|1|0|1|1|0|0|1| +``` + +### Número decimal no ecrã + +89 + +### Ovos reais no galinheiro + +4 + +## Exemplo 2 + +![Sete ninhos individuais dispostos numa fila, em que só o quarto ninho tem um ovo.](https://assets.exercism.org/images/exercises/eliuds-eggs/example-2-coop.svg) + +```text + _ _ _ _ _ _ _ +| | | |E| | | | +``` + +### Binário resultante + +![0001000](https://assets.exercism.org/images/exercises/eliuds-eggs/example-2-binary.svg) + +```text + _ _ _ _ _ _ _ +|0|0|0|1|0|0|0| +``` + +### Número decimal no ecrã + +8 + +### Ovos reais no galinheiro + +1 + +## Instructions + +A tua tarefa é contar o número de bits iguais a 1 na representação binária de um número. + +## Restrições + +Não mexas nessa funcionalidade de contagem de bits fornecida pela tua biblioteca padrão! +Resolve isto sozinho, recorrendo antes a outras ferramentas básicas. + +## Source + +### Created by + +- @vaeng + +### Based on + +Christian Willner, Eric Willigers - https://forum.exercism.org/t/new-exercise-suggestion-pop-count/7632/5 \ No newline at end of file diff --git a/python/eliuds-eggs/__pycache__/eliuds_eggs.cpython-314.pyc b/python/eliuds-eggs/__pycache__/eliuds_eggs.cpython-314.pyc new file mode 100644 index 0000000..8a2b005 Binary files /dev/null and b/python/eliuds-eggs/__pycache__/eliuds_eggs.cpython-314.pyc differ diff --git a/python/eliuds-eggs/__pycache__/eliuds_eggs_test.cpython-314-pytest-9.1.0.pyc b/python/eliuds-eggs/__pycache__/eliuds_eggs_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..8c71eed Binary files /dev/null and b/python/eliuds-eggs/__pycache__/eliuds_eggs_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/eliuds-eggs/eliuds_eggs.py b/python/eliuds-eggs/eliuds_eggs.py new file mode 100644 index 0000000..b9e035e --- /dev/null +++ b/python/eliuds-eggs/eliuds_eggs.py @@ -0,0 +1,17 @@ +def egg_count(display_value): + number_of_eggs: int = 0 + weight: int = 1 + while display_value % weight != display_value: + weight *= 2 + while display_value: + if display_value == weight: + number_of_eggs += 1 + display_value -= weight + if display_value < weight: + weight //= 2 + continue + if display_value % weight: + number_of_eggs += 1 + display_value -= weight + weight //= 2 + return number_of_eggs diff --git a/python/eliuds-eggs/eliuds_eggs_test.py b/python/eliuds-eggs/eliuds_eggs_test.py new file mode 100644 index 0000000..d093e02 --- /dev/null +++ b/python/eliuds-eggs/eliuds_eggs_test.py @@ -0,0 +1,27 @@ +# These tests are auto-generated with test data from: +# https://github.com/exercism/problem-specifications/tree/main/exercises/eliuds-eggs/canonical-data.json +# File last updated on 2024-02-02 + +import unittest + +from eliuds_eggs import ( + egg_count, +) + + +class EliudsEggsTest(unittest.TestCase): + def test_0_eggs(self): + expected = 0 + self.assertEqual(egg_count(0), expected) + + def test_1_egg(self): + expected = 1 + self.assertEqual(egg_count(16), expected) + + def test_4_eggs(self): + expected = 4 + self.assertEqual(egg_count(89), expected) + + def test_13_eggs(self): + expected = 13 + self.assertEqual(egg_count(2000000000), expected) diff --git a/python/ellens-alien-game/.exercism/config.json b/python/ellens-alien-game/.exercism/config.json new file mode 100644 index 0000000..111ebdc --- /dev/null +++ b/python/ellens-alien-game/.exercism/config.json @@ -0,0 +1,24 @@ +{ + "authors": [ + "PaulT89", + "BethanyG" + ], + "contributors": [ + "DjangoFett", + "kotp", + "IsaacG" + ], + "files": { + "solution": [ + "classes.py" + ], + "test": [ + "classes_test.py" + ], + "exemplar": [ + ".meta/exemplar.py" + ] + }, + "icon": "character-study", + "blurb": "Learn about classes by creating an Alien for Ellen's game." +} diff --git a/python/ellens-alien-game/.exercism/metadata.json b/python/ellens-alien-game/.exercism/metadata.json new file mode 100644 index 0000000..db4c6eb --- /dev/null +++ b/python/ellens-alien-game/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"ellens-alien-game","id":"93900682dcdf4ccd8e1eb9ff17859ab7","url":"https://exercism.org/tracks/python/exercises/ellens-alien-game","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/ellens-alien-game/HELP.md b/python/ellens-alien-game/HELP.md new file mode 100644 index 0000000..050813b --- /dev/null +++ b/python/ellens-alien-game/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +
+ +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit classes.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/ellens-alien-game/HINTS.md b/python/ellens-alien-game/HINTS.md new file mode 100644 index 0000000..cede607 --- /dev/null +++ b/python/ellens-alien-game/HINTS.md @@ -0,0 +1,42 @@ +# Hints + +## 1. Create the Alien Class + +- Remember that `object methods` are always passed `self` as the first parameter. +- Remember the double underscores on _both_ sides of `__init__()`. +- Instance variables are unique to the `class` instance (_object_) that possesses them. +- Class variables are the same across all instances of a `class`. + +## 2. The `hit` Method + +- Remember that `object methods` are always passed `self` as the first parameter. +- You can choose to allow the Alien's health to fall below zero, or require that it does not. + +## 3. The `is_alive` Method + +- Remember that `object methods` are always passed `self` as the first parameter. +- 0 may not be the only 'dead' condition, depending on how `hit()` is implemented. + +## 4. The `teleport` Method + +- Remember that `object methods` are always passed `self` as the first parameter. +- Instance attributes can be updated from a method by using `self.` = ``. + +## 5. The `collision_detection` Method + +- Remember that `object methods` are always passed `self` as the first parameter. +- This method seems like an excellent place to use some kind of placeholder… + +## 6. Alien Counter + +- Class attributes are the same across all instances of a `class`. +- Ideally, this counter would increment whenever someone _made an new Alien_. +- Class attributes can be changed from an instance method by using the _class name_: `Alien.`. +- `__init__()` is considered an instance method since it _initializes a new object_. + +## 7. Object Creation + +- A `tuple` would be a _single_ parameter. +- The Alien constructor takes _2 parameters_. +- Unpacking what is _inside_ the tuple would yield two parameters. +- The standalone function is outside of the `class` \ No newline at end of file diff --git a/python/ellens-alien-game/README.md b/python/ellens-alien-game/README.md new file mode 100644 index 0000000..1464768 --- /dev/null +++ b/python/ellens-alien-game/README.md @@ -0,0 +1,415 @@ +# Ellen's Alien Game + +Welcome to Ellen's Alien Game on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. +If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :) + +## Introduction + +## Object Oriented Programming in Python + +If you have been programming in a [functional][functional], [declarative][declarative], or [imperative][imperative] style, shifting focus to [object oriented programming][oop] (OOP) may feel a bit foreign. +An OOP approach asks the programmer to think about modeling a problem as one or more `objects` that interact with one another, keep state, and act upon data. +Objects can represent real world entities (_such as cars or cats_) - or more abstract concepts (_such as integers, vehicles, or mammals_). +Each object becomes a unique instance in computer memory and represents some part of the overall model. + +## Classes + +`Classes` are the definitions of new object types, and from which new `instances` of objects are created. +They often bundle data with code or functions that operate on that data. +In this sense, classes are _blueprints_ or sets of instructions from which many objects of a similar type can be built and used. +A complex program can have many classes, each building many different flavors of objects. +The process of building an object from a class is known as `instantiation` (_or creating an instance of the class_). + +A class definition in Python is straightforward: + +```python +class MyClass: + # Class body goes here +``` + +### Class Attributes + +Class fields (_otherwise known as `properties`, `attributes`, `data members`, or `variables`_) can be added to the body of the class: + +```python +class MyClass: + number = 5 + string = "Hello!" +``` + +An instance (_object_) of `MyClass` can be created and bound to a name by [_calling_][calling] the class (_in the same way a function is called_): + +```python +>>> new_object = MyClass() + +# Class is instantiated and resulting object is bound to the "new_object" name. +# Note: the object address 'at 0x15adc55b0' will vary by computer. +>>> new_object +<__main__.MyClass at 0x15adc55b0> +``` + +`Class attributes` are shared across all objects (_or instances_) created from a class, and can be accessed via [`dot notation`][dot notation] - a `.` placed after the object name and before the attribute name: + +```python +>>> new_object = MyClass() + +# Accessing the class attribute "number" via dot-notation. +>>> new_object.number +5 + +# Accessing the class attribute "string" via dot-notation. +>>> new_object.string +'Hello!' + +# Instantiating an additional object and binding it to the "second_new_object" name. +>>> second_new_object = MyClass() + +>>> second_new_object +# Note: the object address "at 0x15ad99970" will vary by computer. +<__main__.MyClass at 0x15ad99970> + +# Second_new_object shares the same class attributes as new_object. +>>> new_object.number == second_new_object.number +True +``` + +Class attributes are defined in the body of the class itself, before any other methods. +They are owned by the class - allowing them to be shared across instances of the class. +Because these attributes are shared, their value can be accessed and manipulated from the class _directly_. +Altering the value of class attributes alters the value _**for all objects instantiated from the class**_: + +```python +>>> obj_one = MyClass() +>>> obj_two = MyClass() + +# Accessing a class attribute from an object. +>>> obj_two.number +5 + +# Accessing the class attribute from the class itself. +>>> MyClass.number +5 + +# Modifying the value of the "number" class attribute. +>>> MyClass.number = 27 + +# Modifying the "number" class attribute changes the "number" attribute for all objects. +>>> obj_one.number +27 + +>>> obj_two.number +27 +``` + +Having a bunch of objects with synchronized data at all times is not particularly useful. +Fortunately, objects created from a class can be customized with their own `instance attributes` (_or instance properties, variables, or fields_). +As their name suggests, instance attributes are unique to each object, and can be modified independently. + + +## Customizing Object Instantiation with `__init__()` + +The special ["dunder method"][dunder] (_short for "double underscore method"_) `__init__()` is used to customize class instances, and can be used to initialize instance attributes or properties for objects. +For its role in initializing instance attributes, `__init__()` is also referred to as a `class constructor` or `initializer`. +`__init__()` takes one required parameter called `self`, which refers to the newly initialized or created object. +Data for instance attributes or properties can then be passed as arguments of `__init__()`, following the `self` parameter. + +Below, `MyClass` now has instance attributes called `location_x` and `location_y`. +As you can see, the two attributes have been assigned to the first and second indexes of the `location` (_a tuple_) argument that has been passed to `__init__()`. +The `location_x` and `location_y` attributes for a class instance will now be initialized when you instantiate the class, and an object is created: + +```python +class MyClass: + # These are class attributes, variables, or fields. + number = 5 + string = "Hello!" + + # This is the class "constructor", with a "location" parameter that is a tuple. + def __init__(self, location): + + # This is an instance or object property, attribute, or variable. + # Note that we are unpacking the tuple argument into two separate instance variables. + self.location_x = location[0] + self.location_y = location[1] + +# Create a new object "new_object_one", with object property (1, 2). +>>> new_object_one = MyClass((1, 2)) + +# Create a second new object "new_object_two" with object property (-8, -9). +>>> new_object_two = MyClass((-8, -9)) + +# Note that new_object_one.location_x and new_object_two.location_x two different values. +>>> new_object_one.location_x +1 + +>>> new_object_two.location_x +-8 +``` + +Note that you only need to pass one argument when initializing `MyClass` above -- Python takes care of passing `self` when the class is called. + + +## Methods + +A `method` is a `function` that is bound to either the class itself (_known as a [class method][class method], which will be discussed in a later exercise_) or an _instance_ of the class (object). +Methods that operate on an object (instance) need to be defined with `self` as the first parameter. +You can then define the rest of the parameters as you would for a "normal" or non-bound function: + +```python +class MyClass: + number = 5 + string = "Hello!" + + # Class constructor. + def __init__(self, location): + # Instance properties + self.location_x = location[0] + self.location_y = location[1] + + # Instance method. Note "self" as first parameter. + def change_location(self, amount): + self.location_x += amount + self.location_y += amount + return self.location_x, self.location_y +``` + +Like attribute access, calling a method simply requires putting a `.` after the object name, and before the method name. +The called method does not need a copy of the object as a first parameter -- Python fills in `self` automatically: + +```python +class MyClass: + number = 5 + string = "Hello!" + + def __init__(self, location): + self.location_x = location[0] + self.location_y = location[1] + + def change_location(self, amount): + self.location_x += amount + self.location_y += amount + return self.location_x, self.location_y + +# Make a new test_object with location (3,7) +>>> test_object = MyClass((3,7)) +>>> (test_object.location_x, test_object.location_y) +(3,7) + +# Call change_location to increase location_x and location_y by 7. +>>> test_object.change_location(7) +(10, 14) +``` + +Class attributes can be accessed from within instance methods in the same way that they are accessed outside of the class: + +```python +class MyClass: + number = 5 + string = "Hello!" + + def __init__(self, location): + self.location_x = location[0] + self.location_y = location[1] + + # Alter instance variable location_x and location_y + def change_location(self, amount): + self.location_x += amount + self.location_y += amount + return self.location_x, self.location_y + + # Alter class variable number for all instances from within an instance. + def increment_number(self): + # Increment the 'number' class variable by 1. + MyClass.number += 1 + + +>>> test_object_one = MyClass((0,0)) +>>> test_object_one.number +5 + +>>> test_object_two = MyClass((13, -3)) +>>> test_object_two.increment_number() +>>> test_object_one.number +6 +``` + +## Placeholding or Stubbing Implementation with Pass + +In previous concept exercises and practice exercise stubs, you will have seen the `pass` keyword used within the body of functions in place of actual code. +The `pass` keyword is a syntactically valid placeholder - it prevents Python from throwing a syntax error for an empty function or class definition. +Essentially, it is a way to say to the Python interpreter, 'Don't worry! I _will_ put code here eventually, I just haven't done it yet.' + +```python +class MyClass: + number = 5 + string = "Hello!" + + def __init__(self, location): + self.location_x = location[0] + self.location_y = location[1] + + # Alter instance variable location_x and location_y + def change_location(self, amount): + self.location_x += amount + self.location_y += amount + return self.location_x, self.location_y + + # Alter class variable number for all instances + def increment_number(self): + # Increment the 'number' class variable by 1. + MyClass.number += 1 + + # This will compile and run without error, but has no current functionality. + def pending_functionality(self): + # Stubbing or placholding the body of this method. + pass +``` + +[calling]: https://www.pythonmorsels.com/topics/calling-a-function +[class method]: https://stackoverflow.com/questions/17134653/difference-between-class-and-instance-methods +[dunder]: https://mathspp.com/blog/pydonts/dunder-methods +[imperative]: https://en.wikipedia.org/wiki/Imperative_programming +[declarative]: https://en.wikipedia.org/wiki/Declarative_programming +[oop]: https://www.digitalocean.com/community/tutorials/how-to-construct-classes-and-define-objects-in-python-3 +[functional]: https://en.wikipedia.org/wiki/Functional_programming +[dot notation]: https://stackoverflow.com/questions/45179186/understanding-the-dot-notation-in-python + +## Instructions + +Ellen is making a game where the player has to fight aliens. +She has just learned about Object Oriented Programming (OOP) and is eager to take advantage of what using `classes` could offer her program. + +To Ellen's delight, you have offered to help and she has given you the task of programming the aliens that the player has to fight. + + +## 1. Create the Alien Class + +Define the Alien class with a constructor that accepts two parameters `` and ``, putting them into `x_coordinate` and `y_coordinate` instance variables. +Every alien will also start off with a health level of 3, so the `health` variable should be initialized as well. + +```python +>>> alien = Alien(2, 0) +>>> alien.x_coordinate +2 +>>> alien.y_coordinate +0 +>>> alien.health +3 +``` + +Now, each alien should be able to internally track its own position and health. + +## 2. The `hit` Method + +Ellen would like the Alien `class` to have a `hit` method that decrements the health of an alien object by 1 when called. +This way, she can simply call `.hit()` instead of having to manually change an alien's health. +It is up to you if `hit()` takes healths points _to_ or _below_ zero. + +```python +>>> alien = Alien(0, 0) +>>> alien.health + +# Initialized health value. +3 + +# Decrements health by 1 point. +>>> alien.hit() +>>> alien.health +2 +``` + +## 3. The `is_alive` Method + +You realize that if the health keeps decreasing, at some point it will probably hit 0 (_or even less!_). +It would be a good idea to add an `is_alive` method that Ellen can quickly call to check if the alien is... well... alive. 😉 +`.is_alive()` should return a boolean. + +```python +>>> alien.health +1 +>>> alien.is_alive() +True +>>> alien.hit() +>>> alien.health +0 +>>> alien.is_alive() +False +``` + +## 4. The `teleport` Method + +In Ellen's game, the aliens have the ability to teleport! +You will need to write a `teleport` method that takes new `x_coordinate` and `y_coordinate` values, and changes the alien's coordinates accordingly. + +```python +>>> alien.teleport(5, -4) +>>> alien.x_coordinate +5 +>>> alien.y_coordinate +-4 +``` + +## 5. The `collision_detection` Method + +Obviously, if the aliens can be hit by something, then they need to be able to detect when such a collision has occurred. +However, collision detection algorithms can be tricky, and you do not yet know how to implement one. +Ellen has said that she will do it later, but she would still like the `collision_detection` method to appear in the class as a reminder to build out the functionality. +It will need to take a variable of some kind (probably another object), but that's really all you know. +You will need to make sure that putting the method definition into the class doesn't cause any errors when called: + +```python +>>> alien.collision_detection(other_object) +>>> +``` + +## 6. Alien Counter + +Ellen has come back with a new request for you. +She wants to keep track of how many aliens have been created over the game's lifetime. +She says that it's got something to do with the scoring system. + +For example: + +```python +>>> alien_one = Alien(5, 1) +>>> alien_one.total_aliens_created +1 +>>> alien_two = Alien(3, 0) +>>> alien_two.total_aliens_created +2 +>>> alien_one.total_aliens_created +2 +>>> Alien.total_aliens_created +# Accessing the variable from the class directly +2 +``` + +## 7. Creating a List of Aliens + +Ellen loves what you've done so far, but she has one more favor to ask. +She would like a standalone (_outside the `Alien()` class_) function that creates a `list` of `Alien()` objects, given a list of positions (as `tuples`). + +For example: + +```python +>>> alien_start_positions = [(4, 7), (-1, 0)] +>>> aliens = new_aliens_collection(alien_start_positions) +... +>>> for alien in aliens: + print(alien.x_coordinate, alien.y_coordinate) +(4, 7) +(-1, 0) +``` + +## Source + +### Created by + +- @PaulT89 +- @BethanyG + +### Contributed to by + +- @DjangoFett +- @kotp +- @IsaacG \ No newline at end of file diff --git a/python/ellens-alien-game/__pycache__/classes.cpython-313.pyc b/python/ellens-alien-game/__pycache__/classes.cpython-313.pyc new file mode 100644 index 0000000..31fc575 Binary files /dev/null and b/python/ellens-alien-game/__pycache__/classes.cpython-313.pyc differ diff --git a/python/ellens-alien-game/__pycache__/classes.cpython-314.pyc b/python/ellens-alien-game/__pycache__/classes.cpython-314.pyc new file mode 100644 index 0000000..171911c Binary files /dev/null and b/python/ellens-alien-game/__pycache__/classes.cpython-314.pyc differ diff --git a/python/ellens-alien-game/__pycache__/classes_test.cpython-313-pytest-8.3.4.pyc b/python/ellens-alien-game/__pycache__/classes_test.cpython-313-pytest-8.3.4.pyc new file mode 100644 index 0000000..ed324ca Binary files /dev/null and b/python/ellens-alien-game/__pycache__/classes_test.cpython-313-pytest-8.3.4.pyc differ diff --git a/python/ellens-alien-game/__pycache__/classes_test.cpython-314-pytest-9.1.0.pyc b/python/ellens-alien-game/__pycache__/classes_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..d5f9943 Binary files /dev/null and b/python/ellens-alien-game/__pycache__/classes_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/ellens-alien-game/classes.py b/python/ellens-alien-game/classes.py new file mode 100644 index 0000000..1848b20 --- /dev/null +++ b/python/ellens-alien-game/classes.py @@ -0,0 +1,54 @@ +"""Solution to Ellen's Alien Game exercise.""" + + +class Alien: + """Create an Alien object with location x_coordinate and y_coordinate. + + Attributes + ---------- + (class)total_aliens_created: int + x_coordinate: int - Position on the x-axis. + y_coordinate: int - Position on the y-axis. + health: int - Number of health points. + + Methods + ------- + hit(): Decrement Alien health by one point. + is_alive(): Return a boolean for if Alien is alive (if health is > 0). + teleport(new_x_coordinate, new_y_coordinate): Move Alien object to new coordinates. + collision_detection(other): Implementation TBD. + """ + + total_aliens_created: int = 0 + x_coordinate: int + y_coordinate: int + health: int + + def __init__(self, x_coordinate: int, y_coordinate: int) -> None: + self.x_coordinate = x_coordinate + self.y_coordinate = y_coordinate + self.health = 3 + Alien.total_aliens_created += 1 + + def hit(self): + self.health -= 1 + + def is_alive(self) -> bool: + return self.health > 0 + + def teleport(self, new_x_coordinate: int, new_y_coordinate: int): + self.x_coordinate = new_x_coordinate + self.y_coordinate = new_y_coordinate + + def collision_detection(self, other): + pass + + pass + + +# TODO: create the new_aliens_collection() function below to call your Alien class with a list of coordinates. +def new_aliens_collection(list_positions: list[tuple[int, int]]) -> list[Alien]: + list_of_aliens: list[Alien] = [] + for alien_position_x, alien_position_y in list_positions: + list_of_aliens.append(Alien(alien_position_x, alien_position_y)) + return list_of_aliens diff --git a/python/ellens-alien-game/classes_test.py b/python/ellens-alien-game/classes_test.py new file mode 100644 index 0000000..3d2b986 --- /dev/null +++ b/python/ellens-alien-game/classes_test.py @@ -0,0 +1,212 @@ +import unittest +import pytest + + +try: + from classes import Alien +except ImportError as import_fail: + # pylint: disable=raise-missing-from + raise ImportError("\n\nMISSING CLASS --> We tried to import the 'Alien' class from " + "your classes.py file, but could not find it." + "Did you misname or forget to create it?") from None + +try: + from classes import new_aliens_collection +except ImportError as err: + raise ImportError("\n\nMISSING FUNCTION --> We tried to import the " + "new_aliens_collection() function " + "from your classes.py file, but could not find it. " + "Did you misname or forget to create it?") from None + + +class ClassesTest(unittest.TestCase): + + @pytest.mark.task(taskno=1) + def test_alien_has_correct_initial_coordinates(self): + """Test that the Alien class gets correctly initialised.""" + + alien = Alien(2, -1) + error_message = (f'Created a new Alien by calling Alien(2, -1). ' + f'The Alien was initialized to position ' + f'{(alien.x_coordinate, alien.y_coordinate)}, but the tests expected ' + f'the object to be at position (2, -1)') + + self.assertEqual((2, -1), (alien.x_coordinate, alien.y_coordinate), msg=error_message) + + @pytest.mark.task(taskno=1) + def test_alien_has_health(self): + alien = Alien(0, 0) + error_message = (f'Created a new Alien by calling Alien(0, 0). ' + f'The new Alien has a health of {alien.health}, ' + f'but the tests expect health = 3') + + self.assertEqual(3, alien.health, msg=error_message) + + @pytest.mark.task(taskno=1) + def test_alien_instance_variables(self): + """Test instance variables are unique to specific instances.""" + + alien_one = Alien(-8, -1) + alien_two = Alien(2, 5) + + coord_x_error = (f'Created two new Aliens by assigning ' + f'alien_one = Alien(-8, -1) and alien_two = Alien(2, 5). ' + f'Both Aliens x coordinates were {alien_two.x_coordinate}, ' + f'but the tests expect alien_one and alien_two to have ' + f'different x positions.') + + coord_y_error = (f'Created two new Aliens by assigning ' + f'alien_one = Alien(-8, -1) and alien_two = Alien(2, 5). ' + f'Both Aliens y coordinates were {alien_two.y_coordinate}, ' + f'but the tests expect alien_one and alien_two to have ' + f'different y positions.') + + self.assertFalse(alien_one.x_coordinate == alien_two.x_coordinate, msg=coord_x_error) + self.assertFalse(alien_one.y_coordinate == alien_two.y_coordinate, msg=coord_y_error) + + + @pytest.mark.task(taskno=2) + def test_alien_hit_method(self): + """Test class methods work as specified. + + There are two valid interpretations for this method/task. + `self.health -= 1` and `self.health = max(0, self.health - 1)` + The tests for this task reflect this ambiguity. + + """ + + test_data = [1, 2, 3, 4, 5, 6] + result_data = [(2,), (1,), (0,), (0, -1), (0, -2), (0, -3)] + + for variant, (iterations, expected) in enumerate(zip(test_data, result_data), start=1): + alien = Alien(2, 2) + + with self.subTest(f'variation #{variant}', + iterations=iterations, + expected=expected): + + for _ in range(iterations): + alien.hit() + + error_message = (f'Called hit() {iterations} time(s) ' + f'on a newly created Alien. The Aliens health ' + f'is now {alien.health}, but the tests expected ' + f'it to be in {expected} after decrementing 1 health ' + f'point {iterations} time(s).') + + self.assertIn(alien.health, expected, msg=error_message) + + + @pytest.mark.task(taskno=3) + def test_alien_is_alive_method(self): + alien = Alien(0, 1) + + alive_error = ('Created a new Alien and called hit(). ' + 'The function is_alive() is returning False (dead) ' + 'while alien.health is greater than 0.') + + dead_error = ('Created a new Alien and called hit(). ' + 'The function is_alive() is returning True (alive) ' + 'while alien.health is less than or equal to 0.') + + for _ in range(5): + alien.hit() + if alien.health > 0: + self.assertTrue(alien.is_alive(), msg=alive_error) + else: + self.assertFalse(alien.is_alive(), msg=dead_error) + + @pytest.mark.task(taskno=4) + def test_alien_teleport_method(self): + alien = Alien(0, 0) + alien.teleport(-1, -4) + + error_message = ('Called alien.teleport(-1,-4) on a newly created Alien. ' + 'The Alien was found at position ' + f'{(alien.x_coordinate, alien.y_coordinate)}, but the ' + 'tests expected it at position (-1, -4).') + + self.assertEqual((-1, -4), (alien.x_coordinate, alien.y_coordinate), msg=error_message) + + @pytest.mark.task(taskno=5) + def test_alien_collision_detection_method(self): + alien = Alien(7, 3) + error_message = ('Created a new Alien at (7,3) and called ' + 'alien.collision_detection(Alien(7, 2)). ' + f'The method returned {alien.collision_detection(Alien(7, 2))}, ' + 'but the tests expected None. ') + + self.assertIsNone(alien.collision_detection(Alien(7, 2)), msg=error_message) + + + @pytest.mark.task(taskno=6) + def test_alien_class_variable(self): + """Test class attribute/variables are identical across instances.""" + + alien_one, alien_two = Alien(0, 2), Alien(-6, -1) + Alien.health = 6 + + created_error_message = ('Created two new Aliens and requested the ' + 'total_aliens_created attribute for each one. ' + f'Received {alien_one.total_aliens_created, alien_two.total_aliens_created} ' + f'for total_aliens_created, but the tests expect ' + f'the class attributes for each newly created Alien to be identical. ') + + health_error_message = ('Created two new Aliens and requested the ' + f'health attribute for each one. Received {alien_one.health, alien_two.health} ' + 'for health, but the tests expect the class ' + 'attributes for each newly created Alien to be identical. ') + + self.assertEqual(alien_two.total_aliens_created, + alien_one.total_aliens_created, + msg=created_error_message) + + self.assertEqual(alien_two.health, + alien_one.health, + msg=health_error_message) + + @pytest.mark.task(taskno=6) + def test_alien_total_aliens_created(self): + """Test total_aliens_created class variable increments upon object instantiation.""" + + Alien.total_aliens_created = 0 + aliens = [Alien(-2, 6)] + + error_message = ('Created a new Alien and called total_aliens_created for it. ' + f'{aliens[0].total_aliens_created} was returned, but ' + 'the tests expected that total_aliens_created would equal 1.') + + self.assertEqual(1, aliens[0].total_aliens_created, msg=error_message) + + aliens.append(Alien(3, 5)) + aliens.append(Alien(-5, -5)) + + def error_text(alien, variable): + return ('Created two additional Aliens for the session.' + f"Alien number {alien}'s total_aliens_created variable " + f"is equal to {variable}, but the tests expected all " + 'total_aliens_created variables for all instances to be ' + 'equal to number of alien instances created (i.e. 3).') + + self.assertEqual(3, aliens[0].total_aliens_created, msg=error_text(1, aliens[0])) + self.assertEqual(3, aliens[1].total_aliens_created, msg=error_text(2, aliens[1])) + self.assertEqual(3, aliens[2].total_aliens_created, msg=error_text(3, aliens[2])) + + @pytest.mark.task(taskno=7) + def test_new_aliens_collection(self): + """Test that the user knows how to create objects themselves.""" + + test_data = [(-2, 6), (1, 5), (-4, -3)] + actual_result = new_aliens_collection(test_data) + + error_message = "new_aliens_collection() must return a list of Alien objects." + + for obj in actual_result: + self.assertIsInstance(obj, Alien, msg=error_message) + + for position, obj in zip(test_data, actual_result): + position_error = (f'After calling new_aliens_collection({test_data}), ' + f'found {obj} initialized to position {(obj.x_coordinate, obj.y_coordinate)}, ' + f'but the tests expected {obj} to be at position {position} instead.') + + self.assertEqual(position, (obj.x_coordinate, obj.y_coordinate), msg=position_error) diff --git a/python/etl/.exercism/config.json b/python/etl/.exercism/config.json new file mode 100644 index 0000000..32aab8b --- /dev/null +++ b/python/etl/.exercism/config.json @@ -0,0 +1,33 @@ +{ + "authors": [], + "contributors": [ + "alirezaghey", + "behrtam", + "cmccandless", + "Dog", + "etrepum", + "ikhadykin", + "kytrinyx", + "lowks", + "Mofeywalker", + "N-Parsons", + "pheanex", + "sjakobi", + "tqa236", + "yawpitch" + ], + "files": { + "solution": [ + "etl.py" + ], + "test": [ + "etl_test.py" + ], + "example": [ + ".meta/example.py" + ] + }, + "blurb": "Change the data format for scoring a game to more easily add other languages.", + "source": "Based on an exercise by the JumpstartLab team for students at The Turing School of Software and Design.", + "source_url": "https://turing.edu" +} diff --git a/python/etl/.exercism/metadata.json b/python/etl/.exercism/metadata.json new file mode 100644 index 0000000..3cf473a --- /dev/null +++ b/python/etl/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"etl","id":"ed5a9beebea74e5ca3dabd6602d2036a","url":"https://exercism.org/tracks/python/exercises/etl","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/etl/HELP.md b/python/etl/HELP.md new file mode 100644 index 0000000..afd0665 --- /dev/null +++ b/python/etl/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +
+ +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit etl.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/etl/README.md b/python/etl/README.md new file mode 100644 index 0000000..21bc02c --- /dev/null +++ b/python/etl/README.md @@ -0,0 +1,72 @@ +# ETL + +Welcome to ETL on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Introduction + +You work for a company that makes an online multiplayer game called Lexiconia. + +To play the game, each player is given 13 letters, which they must rearrange to create words. +Different letters have different point values, since it's easier to create words with some letters than others. + +The game was originally launched in English, but it is very popular, and now the company wants to expand to other languages as well. + +Different languages need to support different point values for letters. +The point values are determined by how often letters are used, compared to other letters in that language. + +For example, the letter 'C' is quite common in English, and is only worth 3 points. +But in Norwegian it's a very rare letter, and is worth 10 points. + +To make it easier to add new languages, your team needs to change the way letters and their point values are stored in the game. + +## Instructions + +Your task is to change the data format of letters and their point values in the game. + +Currently, letters are stored in groups based on their score, in a one-to-many mapping. + +- 1 point: "A", "E", "I", "O", "U", "L", "N", "R", "S", "T", +- 2 points: "D", "G", +- 3 points: "B", "C", "M", "P", +- 4 points: "F", "H", "V", "W", "Y", +- 5 points: "K", +- 8 points: "J", "X", +- 10 points: "Q", "Z", + +This needs to be changed to store each individual letter with its score in a one-to-one mapping. + +- "a" is worth 1 point. +- "b" is worth 3 points. +- "c" is worth 3 points. +- "d" is worth 2 points. +- etc. + +As part of this change, the team has also decided to change the letters to be lower-case rather than upper-case. + +~~~~exercism/note +If you want to look at how the data was previously structured and how it needs to change, take a look at the examples in the test suite. +~~~~ + +## Source + +### Contributed to by + +- @alirezaghey +- @behrtam +- @cmccandless +- @Dog +- @etrepum +- @ikhadykin +- @kytrinyx +- @lowks +- @Mofeywalker +- @N-Parsons +- @pheanex +- @sjakobi +- @tqa236 +- @yawpitch + +### Based on + +Based on an exercise by the JumpstartLab team for students at The Turing School of Software and Design. - https://turing.edu \ No newline at end of file diff --git a/python/etl/__pycache__/etl.cpython-313.pyc b/python/etl/__pycache__/etl.cpython-313.pyc new file mode 100644 index 0000000..0f6e4ed Binary files /dev/null and b/python/etl/__pycache__/etl.cpython-313.pyc differ diff --git a/python/etl/__pycache__/etl.cpython-314.pyc b/python/etl/__pycache__/etl.cpython-314.pyc new file mode 100644 index 0000000..95bbe96 Binary files /dev/null and b/python/etl/__pycache__/etl.cpython-314.pyc differ diff --git a/python/etl/__pycache__/etl_test.cpython-313-pytest-8.3.5.pyc b/python/etl/__pycache__/etl_test.cpython-313-pytest-8.3.5.pyc new file mode 100644 index 0000000..9b3c6fd Binary files /dev/null and b/python/etl/__pycache__/etl_test.cpython-313-pytest-8.3.5.pyc differ diff --git a/python/etl/__pycache__/etl_test.cpython-314-pytest-9.1.0.pyc b/python/etl/__pycache__/etl_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..86eef92 Binary files /dev/null and b/python/etl/__pycache__/etl_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/etl/etl.py b/python/etl/etl.py new file mode 100644 index 0000000..83629e3 --- /dev/null +++ b/python/etl/etl.py @@ -0,0 +1,5 @@ +def transform(legacy_data: dict[int, list[str]]) -> dict[str, int]: + new_data: dict[str, int] = {} + for key in legacy_data: + new_data.update(dict.fromkeys("".join(legacy_data[key]).lower(), key)) + return new_data diff --git a/python/etl/etl_test.py b/python/etl/etl_test.py new file mode 100644 index 0000000..d6eed70 --- /dev/null +++ b/python/etl/etl_test.py @@ -0,0 +1,66 @@ +# These tests are auto-generated with test data from: +# https://github.com/exercism/problem-specifications/tree/main/exercises/etl/canonical-data.json +# File last updated on 2023-07-19 + +import unittest + +from etl import ( + transform, +) + + +class EtlTest(unittest.TestCase): + def test_single_letter(self): + legacy_data = {1: ["A"]} + data = {"a": 1} + self.assertEqual(transform(legacy_data), data) + + def test_single_score_with_multiple_letters(self): + legacy_data = {1: ["A", "E", "I", "O", "U"]} + data = {"a": 1, "e": 1, "i": 1, "o": 1, "u": 1} + self.assertEqual(transform(legacy_data), data) + + def test_multiple_scores_with_multiple_letters(self): + legacy_data = {1: ["A", "E"], 2: ["D", "G"]} + data = {"a": 1, "d": 2, "e": 1, "g": 2} + self.assertEqual(transform(legacy_data), data) + + def test_multiple_scores_with_differing_numbers_of_letters(self): + legacy_data = { + 1: ["A", "E", "I", "O", "U", "L", "N", "R", "S", "T"], + 2: ["D", "G"], + 3: ["B", "C", "M", "P"], + 4: ["F", "H", "V", "W", "Y"], + 5: ["K"], + 8: ["J", "X"], + 10: ["Q", "Z"], + } + data = { + "a": 1, + "b": 3, + "c": 3, + "d": 2, + "e": 1, + "f": 4, + "g": 2, + "h": 4, + "i": 1, + "j": 8, + "k": 5, + "l": 1, + "m": 3, + "n": 1, + "o": 1, + "p": 3, + "q": 10, + "r": 1, + "s": 1, + "t": 1, + "u": 1, + "v": 4, + "w": 4, + "x": 8, + "y": 4, + "z": 10, + } + self.assertEqual(transform(legacy_data), data) diff --git a/python/flatten-array/.exercism/config.json b/python/flatten-array/.exercism/config.json new file mode 100644 index 0000000..bd0ec35 --- /dev/null +++ b/python/flatten-array/.exercism/config.json @@ -0,0 +1,30 @@ +{ + "authors": [ + "treyhunner" + ], + "contributors": [ + "AiryShift", + "alexpjohnson", + "behrtam", + "cmccandless", + "Dog", + "ikhadykin", + "N-Parsons", + "pheanex", + "tqa236" + ], + "files": { + "solution": [ + "flatten_array.py" + ], + "test": [ + "flatten_array_test.py" + ], + "example": [ + ".meta/example.py" + ] + }, + "blurb": "Take a nested list and return a single list with all values except nil/null.", + "source": "Interview Question", + "source_url": "https://reference.wolfram.com/language/ref/Flatten.html" +} diff --git a/python/flatten-array/.exercism/metadata.json b/python/flatten-array/.exercism/metadata.json new file mode 100644 index 0000000..5952f16 --- /dev/null +++ b/python/flatten-array/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"flatten-array","id":"a92fb57d90ee4bc38b8dd81a658f4d03","url":"https://exercism.org/tracks/python/exercises/flatten-array","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/flatten-array/HELP.md b/python/flatten-array/HELP.md new file mode 100644 index 0000000..c606891 --- /dev/null +++ b/python/flatten-array/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +
+ +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit flatten_array.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/flatten-array/README.md b/python/flatten-array/README.md new file mode 100644 index 0000000..9410a5c --- /dev/null +++ b/python/flatten-array/README.md @@ -0,0 +1,51 @@ +# Flatten Array + +Welcome to Flatten Array on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Introduction + +A shipment of emergency supplies has arrived, but there's a problem. +To protect from damage, the items — flashlights, first-aid kits, blankets — are packed inside boxes, and some of those boxes are nested several layers deep inside other boxes! + +To be prepared for an emergency, everything must be easily accessible in one box. +Can you unpack all the supplies and place them into a single box, so they're ready when needed most? + +## Instructions + +Take a nested array of any depth and return a fully flattened array. + +Note that some language tracks may include null-like values in the input array, and the way these values are represented varies by track. +Such values should be excluded from the flattened array. + +Additionally, the input may be of a different data type and contain different types, depending on the track. + +Check the test suite for details. + +## Example + +input: `[1, [2, 6, null], [[null, [4]], 5]]` + +output: `[1, 2, 6, 4, 5]` + +## Source + +### Created by + +- @treyhunner + +### Contributed to by + +- @AiryShift +- @alexpjohnson +- @behrtam +- @cmccandless +- @Dog +- @ikhadykin +- @N-Parsons +- @pheanex +- @tqa236 + +### Based on + +Interview Question - https://reference.wolfram.com/language/ref/Flatten.html \ No newline at end of file diff --git a/python/flatten-array/__pycache__/flatten_array.cpython-313.pyc b/python/flatten-array/__pycache__/flatten_array.cpython-313.pyc new file mode 100644 index 0000000..667b321 Binary files /dev/null and b/python/flatten-array/__pycache__/flatten_array.cpython-313.pyc differ diff --git a/python/flatten-array/__pycache__/flatten_array.cpython-314.pyc b/python/flatten-array/__pycache__/flatten_array.cpython-314.pyc new file mode 100644 index 0000000..6e3faa3 Binary files /dev/null and b/python/flatten-array/__pycache__/flatten_array.cpython-314.pyc differ diff --git a/python/flatten-array/__pycache__/flatten_array_test.cpython-313-pytest-8.3.5.pyc b/python/flatten-array/__pycache__/flatten_array_test.cpython-313-pytest-8.3.5.pyc new file mode 100644 index 0000000..30c2bc3 Binary files /dev/null and b/python/flatten-array/__pycache__/flatten_array_test.cpython-313-pytest-8.3.5.pyc differ diff --git a/python/flatten-array/__pycache__/flatten_array_test.cpython-314-pytest-9.1.0.pyc b/python/flatten-array/__pycache__/flatten_array_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..9194fa2 Binary files /dev/null and b/python/flatten-array/__pycache__/flatten_array_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/flatten-array/flatten_array.py b/python/flatten-array/flatten_array.py new file mode 100644 index 0000000..3459e72 --- /dev/null +++ b/python/flatten-array/flatten_array.py @@ -0,0 +1,13 @@ +from types import NoneType + + +def flatten(iterable) -> list: + flatten_array: list = [] + for item in iterable: + if isinstance(item, list): + flatten_array.extend(flatten(item)) + elif isinstance(item, NoneType): + continue + else: + flatten_array.append(item) + return flatten_array diff --git a/python/flatten-array/flatten_array_test.py b/python/flatten-array/flatten_array_test.py new file mode 100644 index 0000000..8cd077d --- /dev/null +++ b/python/flatten-array/flatten_array_test.py @@ -0,0 +1,70 @@ +# These tests are auto-generated with test data from: +# https://github.com/exercism/problem-specifications/tree/main/exercises/flatten-array/canonical-data.json +# File last updated on 2025-03-22 + +import unittest + +from flatten_array import ( + flatten, +) + + +class FlattenArrayTest(unittest.TestCase): + def test_empty(self): + inputs = [] + expected = [] + self.assertEqual(flatten(inputs), expected) + + def test_no_nesting(self): + inputs = [0, 1, 2] + expected = [0, 1, 2] + self.assertEqual(flatten(inputs), expected) + + def test_flattens_a_nested_array(self): + inputs = [[[]]] + expected = [] + self.assertEqual(flatten(inputs), expected) + + def test_flattens_array_with_just_integers_present(self): + inputs = [1, [2, 3, 4, 5, 6, 7], 8] + expected = [1, 2, 3, 4, 5, 6, 7, 8] + self.assertEqual(flatten(inputs), expected) + + def test_5_level_nesting(self): + inputs = [0, 2, [[2, 3], 8, 100, 4, [[[50]]]], -2] + expected = [0, 2, 2, 3, 8, 100, 4, 50, -2] + self.assertEqual(flatten(inputs), expected) + + def test_6_level_nesting(self): + inputs = [1, [2, [[3]], [4, [[5]]], 6, 7], 8] + expected = [1, 2, 3, 4, 5, 6, 7, 8] + self.assertEqual(flatten(inputs), expected) + + def test_null_values_are_omitted_from_the_final_result(self): + inputs = [1, 2, None] + expected = [1, 2] + self.assertEqual(flatten(inputs), expected) + + def test_consecutive_null_values_at_the_front_of_the_array_are_omitted_from_the_final_result( + self, + ): + inputs = [None, None, 3] + expected = [3] + self.assertEqual(flatten(inputs), expected) + + def test_consecutive_null_values_in_the_middle_of_the_array_are_omitted_from_the_final_result( + self, + ): + inputs = [1, None, None, 4] + expected = [1, 4] + self.assertEqual(flatten(inputs), expected) + + def test_6_level_nested_array_with_null_values(self): + inputs = [0, 2, [[2, 3], 8, [[100]], None, [[None]]], -2] + expected = [0, 2, 2, 3, 8, 100, -2] + self.assertEqual(flatten(inputs), expected) + + def test_all_values_in_nested_array_are_null(self): + inputs = [None, [[[None]]], None, None, [[None, None], None], None] + expected = [] + self.assertEqual(flatten(inputs), expected) diff --git a/python/ghost-gobble-arcade-game/.exercism/config.json b/python/ghost-gobble-arcade-game/.exercism/config.json new file mode 100644 index 0000000..9065b64 --- /dev/null +++ b/python/ghost-gobble-arcade-game/.exercism/config.json @@ -0,0 +1,26 @@ +{ + "authors": [ + "neenjaw" + ], + "contributors": [ + "cmccandless", + "BethanyG" + ], + "files": { + "solution": [ + "arcade_game.py" + ], + "test": [ + "arcade_game_test.py" + ], + "exemplar": [ + ".meta/exemplar.py" + ] + }, + "language_versions": ">=3.5", + "forked_from": [ + "elixir/pacman-rules" + ], + "icon": "matching-brackets", + "blurb": "Learn about bools by setting up the rules for the Ghost Gobble arcade game." +} diff --git a/python/ghost-gobble-arcade-game/.exercism/metadata.json b/python/ghost-gobble-arcade-game/.exercism/metadata.json new file mode 100644 index 0000000..2c990dd --- /dev/null +++ b/python/ghost-gobble-arcade-game/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"ghost-gobble-arcade-game","id":"c2797792a9de49279f09181e1fb96eda","url":"https://exercism.org/tracks/python/exercises/ghost-gobble-arcade-game","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/ghost-gobble-arcade-game/HELP.md b/python/ghost-gobble-arcade-game/HELP.md new file mode 100644 index 0000000..dc51690 --- /dev/null +++ b/python/ghost-gobble-arcade-game/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +
+ +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit arcade_game.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/ghost-gobble-arcade-game/HINTS.md b/python/ghost-gobble-arcade-game/HINTS.md new file mode 100644 index 0000000..8442c8f --- /dev/null +++ b/python/ghost-gobble-arcade-game/HINTS.md @@ -0,0 +1,26 @@ +# Hints + +## General + +- For an overview, this section of the Python documentation: [Truth Value Testing][stdlib-bools] might help. +- Don't worry about how the arguments are _derived_, focus on combining the arguments to return the intended result. + +## 1. Define if Pac-Man can eat a ghost + +- You can use the [Boolean][boolean] [operators][Boolean-operators] to combine arguments for a result. + +## 2. Define if Pac-Man scores + +- You can use the [Boolean][boolean] [operators][Boolean-operators] to combine arguments for a result. + +## 3. Define if Pac-Man loses + +- You can use the [boolean][Boolean] [operators][Boolean-operators] to combine arguments for a result. + +## 4. Define if Pac-Man wins + +- You can use the [Boolean][boolean] [operators][Boolean-operators] to combine arguments for a result. + +[Boolean-operators]: https://docs.python.org/3/library/stdtypes.html#boolean-operations-and-or-not +[boolean]: https://docs.python.org/3/library/stdtypes.html#truth +[stdlib-bools]: https://docs.python.org/3/library/stdtypes.html#truth-value-testing \ No newline at end of file diff --git a/python/ghost-gobble-arcade-game/README.md b/python/ghost-gobble-arcade-game/README.md new file mode 100644 index 0000000..4bb9306 --- /dev/null +++ b/python/ghost-gobble-arcade-game/README.md @@ -0,0 +1,96 @@ +# Ghost Gobble Arcade Game + +Welcome to Ghost Gobble Arcade Game on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. +If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :) + +## Introduction + +Python represents true and false values with the [`bool`][bools] type, which is a subtype of `int`. + There are only two values in this type: `True` and `False`. + These values can be bound to a variable: + +```python +>>> true_variable = True +>>> false_variable = False +``` + +We can evaluate Boolean expressions using the `and`, `or`, and `not` operators: + +```python +>>> true_variable = True and True +>>> false_variable = True and False + +>>> true_variable = False or True +>>> false_variable = False or False + +>>> true_variable = not False +>>> false_variable = not True +``` + +[bools]: https://docs.python.org/3/library/stdtypes.html#typebool + +## Instructions + +In this exercise, you need to implement some rules from [Pac-Man][Pac-Man], the classic 1980s-era arcade-game. + +You have four rules to implement, all related to the game states. + +> _Do not worry about how the arguments are derived, just focus on combining the arguments to return the intended result._ + +## 1. Define if Pac-Man eats a ghost + +Define the `eat_ghost()` function that takes two parameters (_if Pac-Man has a power pellet active_ and _if Pac-Man is touching a ghost_) and returns a Boolean value if Pac-Man is able to eat a ghost. + The function should return `True` only if Pac-Man has a power pellet active and is touching a ghost. + +```python +>>> eat_ghost(False, True) +... +False +``` + +## 2. Define if Pac-Man scores + +Define the `score()` function that takes two parameters (_if Pac-Man is touching a power pellet_ and _if Pac-Man is touching a dot_) and returns a Boolean value if Pac-Man scored. + The function should return `True` if Pac-Man is touching a power pellet or a dot. + +```python +>>> score(True, True) +... +True +``` + +## 3. Define if Pac-Man loses + +Define the `lose()` function that takes two parameters (_if Pac-Man has a power pellet active_ and _if Pac-Man is touching a ghost_) and returns a Boolean value if Pac-Man loses. + The function should return `True` if Pac-Man is touching a ghost and does not have a power pellet active. + +```python +>>> lose(False, True) +... +True +``` + +## 4. Define if Pac-Man wins + +Define the `win()` function that takes three parameters (_if Pac-Man has eaten all of the dots_, _if Pac-Man has a power pellet active_, and _if Pac-Man is touching a ghost_) and returns a Boolean value if Pac-Man wins. + The function should return `True` if Pac-Man has eaten all of the dots and has not lost based on the parameters defined in part 3. + +```python +>>> win(False, True, False) +... +False +``` + +[Pac-Man]: https://en.wikipedia.org/wiki/Pac-Man + +## Source + +### Created by + +- @neenjaw + +### Contributed to by + +- @cmccandless +- @BethanyG \ No newline at end of file diff --git a/python/ghost-gobble-arcade-game/__pycache__/arcade_game.cpython-313-pytest-8.3.4.pyc b/python/ghost-gobble-arcade-game/__pycache__/arcade_game.cpython-313-pytest-8.3.4.pyc new file mode 100644 index 0000000..070194a Binary files /dev/null and b/python/ghost-gobble-arcade-game/__pycache__/arcade_game.cpython-313-pytest-8.3.4.pyc differ diff --git a/python/ghost-gobble-arcade-game/__pycache__/arcade_game.cpython-313.pyc b/python/ghost-gobble-arcade-game/__pycache__/arcade_game.cpython-313.pyc new file mode 100644 index 0000000..a60bf6d Binary files /dev/null and b/python/ghost-gobble-arcade-game/__pycache__/arcade_game.cpython-313.pyc differ diff --git a/python/ghost-gobble-arcade-game/__pycache__/arcade_game.cpython-314.pyc b/python/ghost-gobble-arcade-game/__pycache__/arcade_game.cpython-314.pyc new file mode 100644 index 0000000..3ee7343 Binary files /dev/null and b/python/ghost-gobble-arcade-game/__pycache__/arcade_game.cpython-314.pyc differ diff --git a/python/ghost-gobble-arcade-game/__pycache__/arcade_game_test.cpython-313-pytest-8.3.4.pyc b/python/ghost-gobble-arcade-game/__pycache__/arcade_game_test.cpython-313-pytest-8.3.4.pyc new file mode 100644 index 0000000..3ef49fe Binary files /dev/null and b/python/ghost-gobble-arcade-game/__pycache__/arcade_game_test.cpython-313-pytest-8.3.4.pyc differ diff --git a/python/ghost-gobble-arcade-game/__pycache__/arcade_game_test.cpython-314-pytest-9.1.0.pyc b/python/ghost-gobble-arcade-game/__pycache__/arcade_game_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..95f0f92 Binary files /dev/null and b/python/ghost-gobble-arcade-game/__pycache__/arcade_game_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/ghost-gobble-arcade-game/arcade_game.py b/python/ghost-gobble-arcade-game/arcade_game.py new file mode 100644 index 0000000..f2c662b --- /dev/null +++ b/python/ghost-gobble-arcade-game/arcade_game.py @@ -0,0 +1,42 @@ +"""Functions for implementing the rules of the classic arcade game Pac-Man.""" + + +def eat_ghost(power_pellet_active: bool, touching_ghost: bool) -> bool: + """Verify that Pac-Man can eat a ghost if he is empowered by a power pellet. + + :param power_pellet_active: bool - does the player have an active power pellet? + :param touching_ghost: bool - is the player touching a ghost? + :return: bool - can a ghost be eaten? + """ + return power_pellet_active and touching_ghost + + +def score(touching_power_pellet: bool, touching_dot: bool) -> bool: + """Verify that Pac-Man has scored when a power pellet or dot has been eaten. + + :param touching_power_pellet: bool - is the player touching a power pellet? + :param touching_dot: bool - is the player touching a dot? + :return: bool - has the player scored or not? + """ + return touching_power_pellet or touching_dot + + +def lose(power_pellet_active, touching_ghost) -> bool: + """Trigger the game loop to end (GAME OVER) when Pac-Man touches a ghost without his power pellet. + + :param power_pellet_active: bool - does the player have an active power pellet? + :param touching_ghost: bool - is the player touching a ghost? + :return: bool - has the player lost the game? + """ + return not power_pellet_active and touching_ghost + + +def win(has_eaten_all_dots, power_pellet_active, touching_ghost) -> bool: + """Trigger the victory event when all dots have been eaten. + + :param has_eaten_all_dots: bool - has the player "eaten" all the dots? + :param power_pellet_active: bool - does the player have an active power pellet? + :param touching_ghost: bool - is the player touching a ghost? + :return: bool - has the player won the game? + """ + return has_eaten_all_dots and not lose(power_pellet_active, touching_ghost) diff --git a/python/ghost-gobble-arcade-game/arcade_game_test.py b/python/ghost-gobble-arcade-game/arcade_game_test.py new file mode 100644 index 0000000..4dc3ca4 --- /dev/null +++ b/python/ghost-gobble-arcade-game/arcade_game_test.py @@ -0,0 +1,144 @@ +import unittest +import pytest +from arcade_game import eat_ghost, score, lose, win + + +class GhostGobbleGameTest(unittest.TestCase): + + @pytest.mark.task(taskno=1) + def test_ghost_gets_eaten(self): + actual_result = eat_ghost(True, True) + error_message = ('Called eat_ghost(True, True).' + f'The function returned {actual_result}, but the ' + f'tests expected that the ghost gets eaten (True).') + + self.assertIs(actual_result, True, msg=error_message) + + @pytest.mark.task(taskno=1) + def test_ghost_does_not_get_eaten_because_no_power_pellet_active(self): + actual_result = eat_ghost(False, True) + error_message = ('Called eat_ghost(False, True).' + f'The function returned {actual_result}, but the ' + f'tests expected that the ' + 'ghost **does not** get eaten because ' + 'no power pellet was active.') + + self.assertIs(actual_result, False, msg=error_message) + + @pytest.mark.task(taskno=1) + def test_ghost_does_not_get_eaten_because_not_touching_ghost(self): + actual_result = eat_ghost(True, False) + error_message = ('Called eat_ghost(True, False).' + f'The function returned {actual_result}, but the ' + f'tests expected that the ' + 'ghost **does not** get eaten because ' + 'the player was not touching the ghost.') + + self.assertIs(actual_result, False, msg=error_message) + + @pytest.mark.task(taskno=2) + def test_score_when_eating_dot(self): + actual_result = score(False, True) + error_message = ('Called score(False, True).' + f'The function returned {actual_result}, but the ' + f'tests expected that the ' + 'player scores because they were touching a dot.') + + self.assertIs(actual_result, True, msg=error_message) + + @pytest.mark.task(taskno=2) + def test_score_when_eating_power_pellet(self): + actual_result = score(True, False) + error_message = ('Called score(True, False).' + f'The function returned {actual_result}, but the ' + f'tests expected that the ' + 'player scores because they ' + 'were touching a power pellet.') + + self.assertIs(actual_result,True,msg=error_message) + + @pytest.mark.task(taskno=2) + def test_no_score_when_nothing_eaten(self): + actual_result = score(False, False) + error_message = ('Called score(False, False).' + f'The function returned {actual_result}, but the ' + f'tests expected that the ' + 'player **does not** score because they ' + 'were not touching anything.') + self.assertIs(actual_result, False,msg=error_message) + + @pytest.mark.task(taskno=3) + def test_lose_if_touching_a_ghost_without_a_power_pellet_active(self): + actual_result = lose(False, True) + error_message = ('Called lose(False, True).' + f'The function returned {actual_result}, but the ' + f'tests expected that the ' + 'player loses because they touched a ' + 'ghost without a power pellet activated.') + self.assertIs( + actual_result, True, msg=error_message) + + @pytest.mark.task(taskno=3) + def test_dont_lose_if_touching_a_ghost_with_a_power_pellet_active(self): + actual_result = lose(True, True) + error_message = ('Called lose(True, True).' + f'The function returned {actual_result}, but the ' + f'tests expected that the ' + 'player **does not** lose because when they touched a ' + 'ghost, a power pellet was active.') + + self.assertIs(actual_result, False, msg=error_message) + + @pytest.mark.task(taskno=3) + def test_dont_lose_if_not_touching_a_ghost(self): + actual_result = lose(True, False) + error_message = ('Called lose(True, False).' + f'The function returned {actual_result}, but the ' + f'tests expected that the ' + 'player **does not** lose because they were ' + 'not touching a ghost.') + + self.assertIs(actual_result, False, msg=error_message) + + @pytest.mark.task(taskno=4) + def test_win_if_all_dots_eaten(self): + actual_result = win(True, False, False) + error_message = ('Called win(True, False, False).' + f'The function returned {actual_result}, but the ' + f'tests expected that the ' + 'player wins because all the dots were eaten.') + + self.assertIs(actual_result, True, msg=error_message) + + @pytest.mark.task(taskno=4) + def test_dont_win_if_all_dots_eaten_but_touching_a_ghost(self): + actual_result = win(True, False, True) + error_message = ('Called win(True, False, True).' + f'The function returned {actual_result}, but the ' + f'tests expected that the ' + 'player **does not** win, because ' + 'the player was touching a ghost.') + + self.assertIs(actual_result, False, msg=error_message) + + @pytest.mark.task(taskno=4) + def test_win_if_all_dots_eaten_and_touching_a_ghost_with_a_power_pellet_active(self): + actual_result = win(True, True, True) + error_message = ('Called win(True, True, True).' + f'The function returned {actual_result}, but the ' + f'tests expected that the player wins, ' + f'because a power pellet was active when they ' + f'touched a ghost.') + + self.assertIs(actual_result, True, msg=error_message) + + @pytest.mark.task(taskno=4) + def test_dont_win_if_not_all_dots_eaten(self): + actual_result = win(False, True, True) + error_message = ('Called win(False, True, True).' + f'The function returned {actual_result}, but the ' + f'tests expected that the player **does not** win, ' + f'because the player did not eat all of the dots.') + + self.assertIs(actual_result, False, msg=error_message) + diff --git a/python/gigasecond/.exercism/config.json b/python/gigasecond/.exercism/config.json new file mode 100644 index 0000000..76af3da --- /dev/null +++ b/python/gigasecond/.exercism/config.json @@ -0,0 +1,35 @@ +{ + "authors": [], + "contributors": [ + "behrtam", + "BethanyG", + "cmccandless", + "Dog", + "etrepum", + "GascaK", + "ikhadykin", + "kytrinyx", + "lowks", + "N-Parsons", + "pamtdoh", + "pheanex", + "sjakobi", + "tqa236", + "yawpitch", + "AndrewLawendy" + ], + "files": { + "solution": [ + "gigasecond.py" + ], + "test": [ + "gigasecond_test.py" + ], + "example": [ + ".meta/example.py" + ] + }, + "blurb": "Given a moment, determine the moment that would be after a gigasecond has passed.", + "source": "Chapter 9 in Chris Pine's online Learn to Program tutorial.", + "source_url": "https://pine.fm/LearnToProgram/?Chapter=09" +} diff --git a/python/gigasecond/.exercism/metadata.json b/python/gigasecond/.exercism/metadata.json new file mode 100644 index 0000000..ad7b341 --- /dev/null +++ b/python/gigasecond/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"gigasecond","id":"4f8eda778f1246189ad8495417846e1d","url":"https://exercism.org/tracks/python/exercises/gigasecond","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/gigasecond/HELP.md b/python/gigasecond/HELP.md new file mode 100644 index 0000000..62d9201 --- /dev/null +++ b/python/gigasecond/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +
+ +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit gigasecond.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/gigasecond/HINTS.md b/python/gigasecond/HINTS.md new file mode 100644 index 0000000..9f25a6c --- /dev/null +++ b/python/gigasecond/HINTS.md @@ -0,0 +1,17 @@ +# Hints + +## General + +- Your function should parse the passed-in [datetime object][datetime], add a gigasecond's worth of time to it, and then return the result. + +- If you're having trouble, remember to take a look at the provided test cases under the Tests tab. These will help you figure out what the expected inputs and outputs of your function(s) should be. + +- Most of the time, code is read rather than written, and a big number can be a challenge to read. Here are a couple of approaches to making big numbers in your code more readable: + + - Using underscores (`_`) in numeric literals can help offset thousands, hundred-thousands, millions, etc. (_**ie:** `1_000_000` or `10_100_201_330` is far more readable than `1000000` or `10100201330`._) See [PEP-0515][underscores_notation] for more information. + + - Scientific notation can be more compact and easier to scan when there are very large numbers (_**ie:** `1e6`, 1 is multiplied by 10 raised to the power of 6, which equals `1000000`_). For more information, see this reference on [scientific notation][scientific_notation]. + +[datetime]: https://docs.python.org/3.9/library/datetime.html#datetime.datetime +[scientific_notation]: https://python-reference.readthedocs.io/en/latest/docs/float/scientific.html +[underscores_notation]: https://peps.python.org/pep-0515/#:~:text=The%20syntax%20would%20be%20the,width%20of%2010%20with%20*%20separator. \ No newline at end of file diff --git a/python/gigasecond/README.md b/python/gigasecond/README.md new file mode 100644 index 0000000..70394f1 --- /dev/null +++ b/python/gigasecond/README.md @@ -0,0 +1,88 @@ +# Gigasecond + +Welcome to Gigasecond on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. +If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :) + +## Introduction + +The way we measure time is kind of messy. +We have 60 seconds in a minute, and 60 minutes in an hour. +This comes from ancient Babylon, where they used 60 as the basis for their number system. +We have 24 hours in a day, 7 days in a week, and how many days in a month? +Well, for days in a month it depends not only on which month it is, but also on what type of calendar is used in the country you live in. + +What if, instead, we only use seconds to express time intervals? +Then we can use metric system prefixes for writing large numbers of seconds in more easily comprehensible quantities. + +- A food recipe might explain that you need to let the brownies cook in the oven for two kiloseconds (that's two thousand seconds). +- Perhaps you and your family would travel to somewhere exotic for two megaseconds (that's two million seconds). +- And if you and your spouse were married for _a thousand million_ seconds, you would celebrate your one gigasecond anniversary. + +~~~~exercism/note +If we ever colonize Mars or some other planet, measuring time is going to get even messier. +If someone says "year" do they mean a year on Earth or a year on Mars? + +The idea for this exercise came from the science fiction novel ["A Deepness in the Sky"][vinge-novel] by author Vernor Vinge. +In it the author uses the metric system as the basis for time measurements. + +[vinge-novel]: https://www.tor.com/2017/08/03/science-fiction-with-something-for-everyone-a-deepness-in-the-sky-by-vernor-vinge/ +~~~~ + +## Instructions + +Your task is to determine the date and time one gigasecond after a certain date. + +A gigasecond is one thousand million seconds. +That is a one with nine zeros after it. + +If you were born on _January 24th, 2015 at 22:00 (10:00:00pm)_, then you would be a gigasecond old on _October 2nd, 2046 at 23:46:40 (11:46:40pm)_. + +## Reading and Writing Long Numbers + +Code is more often _read_ than it is written, and reading a big/long number within other text can be a challenge. +Here are two approaches to making numbers more readable: + +1. Using underscores in Numeric Literals. `1_000_000` is more readable than `1000000`, and `10_100_201_330` is easier to scan than `10100201330`. For more information, see [PEP-0515][underscores_notation]. + +2. Using exponential notation or scientific notation. The e (or E) character followed by an integer represents the power of 10 by which the number preceding the e should be multiplied (_**ie:** `1e6`, 1 is multiplied by 10 raised to the power of 6, which equals `1000000`_). For more details, check out this reference on [scientific notation][scientific_notation]. + + +## Dates and Times in Python + +This exercise explores objects from Python's `datetime` module: + +- [Official Python documentation on the datetime module][datetime] +- [datetime objects][datetime.datetime] +- [timedelta objects][datetime.timedelta] + +[datetime.datetime]: https://docs.python.org/3.9/library/datetime.html#datetime.datetime +[datetime.timedelta]: https://docs.python.org/3.9/library/datetime.html#timedelta-objects +[datetime]: https://docs.python.org/3.9/library/datetime.html#module-datetime +[scientific_notation]: https://python-reference.readthedocs.io/en/latest/docs/float/scientific.html +[underscores_notation]: https://peps.python.org/pep-0515/#:~:text=The%20syntax%20would%20be%20the,width%20of%2010%20with%20*%20separator. + +## Source + +### Contributed to by + +- @behrtam +- @BethanyG +- @cmccandless +- @Dog +- @etrepum +- @GascaK +- @ikhadykin +- @kytrinyx +- @lowks +- @N-Parsons +- @pamtdoh +- @pheanex +- @sjakobi +- @tqa236 +- @yawpitch +- @AndrewLawendy + +### Based on + +Chapter 9 in Chris Pine's online Learn to Program tutorial. - https://pine.fm/LearnToProgram/?Chapter=09 \ No newline at end of file diff --git a/python/gigasecond/__pycache__/gigasecond.cpython-313.pyc b/python/gigasecond/__pycache__/gigasecond.cpython-313.pyc new file mode 100644 index 0000000..c4c48e0 Binary files /dev/null and b/python/gigasecond/__pycache__/gigasecond.cpython-313.pyc differ diff --git a/python/gigasecond/__pycache__/gigasecond.cpython-314.pyc b/python/gigasecond/__pycache__/gigasecond.cpython-314.pyc new file mode 100644 index 0000000..9f43981 Binary files /dev/null and b/python/gigasecond/__pycache__/gigasecond.cpython-314.pyc differ diff --git a/python/gigasecond/__pycache__/gigasecond_test.cpython-313-pytest-8.3.5.pyc b/python/gigasecond/__pycache__/gigasecond_test.cpython-313-pytest-8.3.5.pyc new file mode 100644 index 0000000..7a761f2 Binary files /dev/null and b/python/gigasecond/__pycache__/gigasecond_test.cpython-313-pytest-8.3.5.pyc differ diff --git a/python/gigasecond/__pycache__/gigasecond_test.cpython-314-pytest-9.1.0.pyc b/python/gigasecond/__pycache__/gigasecond_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..5f4cff4 Binary files /dev/null and b/python/gigasecond/__pycache__/gigasecond_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/gigasecond/gigasecond.py b/python/gigasecond/gigasecond.py new file mode 100644 index 0000000..31578cd --- /dev/null +++ b/python/gigasecond/gigasecond.py @@ -0,0 +1,5 @@ +from datetime import datetime, timedelta + + +def add(moment: datetime) -> datetime: + return moment + timedelta(seconds=1_000_000_000) diff --git a/python/gigasecond/gigasecond_test.py b/python/gigasecond/gigasecond_test.py new file mode 100644 index 0000000..dd648e1 --- /dev/null +++ b/python/gigasecond/gigasecond_test.py @@ -0,0 +1,37 @@ +# These tests are auto-generated with test data from: +# https://github.com/exercism/problem-specifications/tree/main/exercises/gigasecond/canonical-data.json +# File last updated on 2023-07-19 + +from datetime import datetime +import unittest + +from gigasecond import ( + add, +) + + +class GigasecondTest(unittest.TestCase): + def test_date_only_specification_of_time(self): + self.assertEqual( + add(datetime(2011, 4, 25, 0, 0)), datetime(2043, 1, 1, 1, 46, 40) + ) + + def test_second_test_for_date_only_specification_of_time(self): + self.assertEqual( + add(datetime(1977, 6, 13, 0, 0)), datetime(2009, 2, 19, 1, 46, 40) + ) + + def test_third_test_for_date_only_specification_of_time(self): + self.assertEqual( + add(datetime(1959, 7, 19, 0, 0)), datetime(1991, 3, 27, 1, 46, 40) + ) + + def test_full_time_specified(self): + self.assertEqual( + add(datetime(2015, 1, 24, 22, 0)), datetime(2046, 10, 2, 23, 46, 40) + ) + + def test_full_time_with_day_roll_over(self): + self.assertEqual( + add(datetime(2015, 1, 24, 23, 59, 59)), datetime(2046, 10, 3, 1, 46, 39) + ) diff --git a/python/grains/.exercism/config.json b/python/grains/.exercism/config.json new file mode 100644 index 0000000..4e59df7 --- /dev/null +++ b/python/grains/.exercism/config.json @@ -0,0 +1,34 @@ +{ + "authors": [], + "contributors": [ + "behrtam", + "BethanyG", + "cmccandless", + "denislooby", + "Dog", + "kytrinyx", + "lowks", + "MojitoMonday", + "N-Parsons", + "pheanex", + "sdublish", + "sjakobi", + "smalley", + "tqa236", + "yawpitch" + ], + "files": { + "solution": [ + "grains.py" + ], + "test": [ + "grains_test.py" + ], + "example": [ + ".meta/example.py" + ] + }, + "blurb": "Calculate the number of grains of wheat on a chessboard given that the number on each square doubles.", + "source": "The CodeRanch Cattle Drive, Assignment 6", + "source_url": "https://coderanch.com/wiki/718824/Grains" +} diff --git a/python/grains/.exercism/metadata.json b/python/grains/.exercism/metadata.json new file mode 100644 index 0000000..95502d7 --- /dev/null +++ b/python/grains/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"grains","id":"67b613ae699b40f69911e1fca861aaf4","url":"https://exercism.org/tracks/python/exercises/grains","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/grains/HELP.md b/python/grains/HELP.md new file mode 100644 index 0000000..1be6a85 --- /dev/null +++ b/python/grains/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +
+ +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit grains.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/grains/README.md b/python/grains/README.md new file mode 100644 index 0000000..9f30d0a --- /dev/null +++ b/python/grains/README.md @@ -0,0 +1,57 @@ +# Grains + +Welcome to Grains on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Instructions + +Calculate the number of grains of wheat on a chessboard given that the number on each square doubles. + +There once was a wise servant who saved the life of a prince. +The king promised to pay whatever the servant could dream up. +Knowing that the king loved chess, the servant told the king he would like to have grains of wheat. +One grain on the first square of a chess board, with the number of grains doubling on each successive square. + +There are 64 squares on a chessboard (where square 1 has one grain, square 2 has two grains, and so on). + +Write code that shows: + +- how many grains were on a given square, and +- the total number of grains on the chessboard + +## Exception messages + +Sometimes it is necessary to [raise an exception](https://docs.python.org/3/tutorial/errors.html#raising-exceptions). When you do this, you should always include a **meaningful error message** to indicate what the source of the error is. This makes your code more readable and helps significantly with debugging. For situations where you know that the error source will be a certain type, you can choose to raise one of the [built in error types](https://docs.python.org/3/library/exceptions.html#base-classes), but should still include a meaningful message. + +This particular exercise requires that you use the [raise statement](https://docs.python.org/3/reference/simple_stmts.html#the-raise-statement) to "throw" a `ValueError` when the square input is out of range. The tests will only pass if you both `raise` the `exception` and include a message with it. + +To raise a `ValueError` with a message, write the message as an argument to the `exception` type: + +```python +# when the square value is not in the acceptable range +raise ValueError("square must be between 1 and 64") +``` + +## Source + +### Contributed to by + +- @behrtam +- @BethanyG +- @cmccandless +- @denislooby +- @Dog +- @kytrinyx +- @lowks +- @MojitoMonday +- @N-Parsons +- @pheanex +- @sdublish +- @sjakobi +- @smalley +- @tqa236 +- @yawpitch + +### Based on + +The CodeRanch Cattle Drive, Assignment 6 - https://coderanch.com/wiki/718824/Grains \ No newline at end of file diff --git a/python/grains/__pycache__/grains.cpython-313.pyc b/python/grains/__pycache__/grains.cpython-313.pyc new file mode 100644 index 0000000..268b8d0 Binary files /dev/null and b/python/grains/__pycache__/grains.cpython-313.pyc differ diff --git a/python/grains/__pycache__/grains.cpython-314.pyc b/python/grains/__pycache__/grains.cpython-314.pyc new file mode 100644 index 0000000..e3dfa7a Binary files /dev/null and b/python/grains/__pycache__/grains.cpython-314.pyc differ diff --git a/python/grains/__pycache__/grains_test.cpython-313-pytest-8.3.4.pyc b/python/grains/__pycache__/grains_test.cpython-313-pytest-8.3.4.pyc new file mode 100644 index 0000000..6ee22ee Binary files /dev/null and b/python/grains/__pycache__/grains_test.cpython-313-pytest-8.3.4.pyc differ diff --git a/python/grains/__pycache__/grains_test.cpython-314-pytest-9.1.0.pyc b/python/grains/__pycache__/grains_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..fe52703 Binary files /dev/null and b/python/grains/__pycache__/grains_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/grains/grains.py b/python/grains/grains.py new file mode 100644 index 0000000..c4e5e31 --- /dev/null +++ b/python/grains/grains.py @@ -0,0 +1,14 @@ +def square(number): + grains: int = 1 + if (number <= 0) or (number > 64): + raise ValueError("square must be between 1 and 64") + for _ in range(1, number): + grains *= 2 + return grains + + +def total(): + total_grains: int = 0 + for square_number in range(1, 65): + total_grains += square(square_number) + return total_grains diff --git a/python/grains/grains_test.py b/python/grains/grains_test.py new file mode 100644 index 0000000..177f91f --- /dev/null +++ b/python/grains/grains_test.py @@ -0,0 +1,54 @@ +# These tests are auto-generated with test data from: +# https://github.com/exercism/problem-specifications/tree/main/exercises/grains/canonical-data.json +# File last updated on 2023-09-27 + +import unittest + +from grains import ( + square, + total, +) + + +class GrainsTest(unittest.TestCase): + def test_grains_on_square_1(self): + self.assertEqual(square(1), 1) + + def test_grains_on_square_2(self): + self.assertEqual(square(2), 2) + + def test_grains_on_square_3(self): + self.assertEqual(square(3), 4) + + def test_grains_on_square_4(self): + self.assertEqual(square(4), 8) + + def test_grains_on_square_16(self): + self.assertEqual(square(16), 32768) + + def test_grains_on_square_32(self): + self.assertEqual(square(32), 2147483648) + + def test_grains_on_square_64(self): + self.assertEqual(square(64), 9223372036854775808) + + def test_square_0_is_invalid(self): + with self.assertRaises(ValueError) as err: + square(0) + self.assertEqual(type(err.exception), ValueError) + self.assertEqual(err.exception.args[0], "square must be between 1 and 64") + + def test_negative_square_is_invalid(self): + with self.assertRaises(ValueError) as err: + square(-1) + self.assertEqual(type(err.exception), ValueError) + self.assertEqual(err.exception.args[0], "square must be between 1 and 64") + + def test_square_greater_than_64_is_invalid(self): + with self.assertRaises(ValueError) as err: + square(65) + self.assertEqual(type(err.exception), ValueError) + self.assertEqual(err.exception.args[0], "square must be between 1 and 64") + + def test_returns_the_total_number_of_grains_on_the_board(self): + self.assertEqual(total(), 18446744073709551615) diff --git a/python/guidos-gorgeous-lasagna/.exercism/config.json b/python/guidos-gorgeous-lasagna/.exercism/config.json new file mode 100644 index 0000000..f6de0d5 --- /dev/null +++ b/python/guidos-gorgeous-lasagna/.exercism/config.json @@ -0,0 +1,22 @@ +{ + "authors": [ + "BethanyG" + ], + "files": { + "solution": [ + "lasagna.py" + ], + "test": [ + "lasagna_test.py" + ], + "exemplar": [ + ".meta/exemplar.py" + ] + }, + "forked_from": [ + "csharp/lucians-luscious-lasagna", + "ruby/lasagna" + ], + "icon": "lasagna", + "blurb": "Learn the basics of Python by cooking Guido's Gorgeous Lasagna." +} diff --git a/python/guidos-gorgeous-lasagna/.exercism/metadata.json b/python/guidos-gorgeous-lasagna/.exercism/metadata.json new file mode 100644 index 0000000..2fbde6f --- /dev/null +++ b/python/guidos-gorgeous-lasagna/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"guidos-gorgeous-lasagna","id":"f936c8fd62ae46d19a8298f527f1298b","url":"https://exercism.org/tracks/python/exercises/guidos-gorgeous-lasagna","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/guidos-gorgeous-lasagna/HELP.md b/python/guidos-gorgeous-lasagna/HELP.md new file mode 100644 index 0000000..36cc8e5 --- /dev/null +++ b/python/guidos-gorgeous-lasagna/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +
+ +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit lasagna.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/guidos-gorgeous-lasagna/HINTS.md b/python/guidos-gorgeous-lasagna/HINTS.md new file mode 100644 index 0000000..e65a517 --- /dev/null +++ b/python/guidos-gorgeous-lasagna/HINTS.md @@ -0,0 +1,51 @@ +# Hints + +## General + +- [The Python Tutorial][the python tutorial] can be a great introduction. +- [PEP 8][pep8] is the Python code style guide. +- [PEP 257][PEP257] details Python docstring conventions. +- [Numbers][numbers] in Python can be integers, floats, or complex. + + +## 1. Define expected bake time in minutes + +- You need to [name][naming] a [constant][constants], and [assign][assignment] it an [integer][numbers] value. + This constant should be the first thing after the docstring that is at the top of the file. + Remember to remove the #TODO comment after defining the constant. + +## 2. Calculate remaining bake time in minutes + +- You need to define a [function][defining functions] with a single parameter representing the time elapsed so far. +- Use the [mathematical operator for subtraction][numbers] to subtract values. +- This function should [return a value][return]. + +## 3. Calculate preparation time in minutes + +- You need to define a [function][defining functions] with a single parameter representing the number of layers. +- Use the [mathematical operator for multiplication][numbers] to multiply values. +- You could define an extra _constant_ for the time in minutes per layer rather than using a "magic number" in your code. +- This function should [return a value][return]. + +## 4. Calculate total elapsed cooking time (prep + bake) in minutes + +- You need to define a [function][defining functions] with two parameters. +- Remember: you can always _call_ a function you've defined previously. +- You can use the [mathematical operator for addition][python as a calculator] to sum values. +- This function should [return a value][return]. + +## 5. Update the recipe with notes + +- Clearly [commenting][comments] and [documenting][docstrings] your code according to [PEP257][pep257] is always recommended. + +[assignment]: https://docs.python.org/3/reference/simple_stmts.html#grammar-token-assignment-stmt +[comments]: https://realpython.com/python-comments-guide/ +[constants]: https://stackoverflow.com/a/2682752 +[defining functions]: https://docs.python.org/3/tutorial/controlflow.html#defining-functions +[docstrings]: https://docs.python.org/3/tutorial/controlflow.html#tut-docstrings +[naming]: https://realpython.com/python-variables/ +[numbers]: https://docs.python.org/3/tutorial/introduction.html#numbers +[pep257]: https://www.python.org/dev/peps/pep-0257/ +[python as a calculator]: https://docs.python.org/3/tutorial/introduction.html#using-python-as-a-calculator +[return]: https://docs.python.org/3/reference/simple_stmts.html#return +[the python tutorial]: https://docs.python.org/3/tutorial/introduction.html \ No newline at end of file diff --git a/python/guidos-gorgeous-lasagna/README.md b/python/guidos-gorgeous-lasagna/README.md new file mode 100644 index 0000000..0d40a5b --- /dev/null +++ b/python/guidos-gorgeous-lasagna/README.md @@ -0,0 +1,359 @@ +# Guido's Gorgeous Lasagna + +Welcome to Guido's Gorgeous Lasagna on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. +If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :) + +## Introduction + +Python is a [dynamic and strongly][dynamic typing in python] typed programming language. +It employs both [duck typing][duck typing] and [gradual typing][gradual typing] via [type hints][type hints]. + +While Python supports many different programming _styles_, internally **everything in Python is an [object][everythings an object]**. +This includes numbers, strings, lists, and even functions. + +We'll dig more into what all of that means as we continue through the track. + +This first exercise introduces 4 major Python language features: +1. Name Assignment (_variables and constants_), +2. Functions (_the `def` keyword and the `return` keyword_), +3. Comments, and +4. Docstrings. + +
+ +~~~~exercism/note + +In general, content, tests, and analyzer tooling for the Python track follow the style conventions outlined in [PEP 8](https://www.python.org/dev/peps/pep-0008/) and [PEP 257](https://www.python.org/dev/peps/pep-0257/) for Python code style, with the additional (strong) suggestion that there be no single letter variable names. + +On the Python track, [variables][variables] are always written in [`snake_case`][snake case], and constants in `SCREAMING_SNAKE_CASE`. + +[variables]: https://realpython.com/python-variables/ +[snake case]: https://en.wikipedia.org/wiki/Snake_case +~~~~ + +
+ +## Name Assignment (Variables & Constants) + +Programmers can bind [_names_][facts-and-myths-about-python-names] (also called _variables_) to any type of object using the assignment `=` operator: ` = `. +A name can be reassigned (or re-bound) to different values (different object types) over its lifetime. + + +```python +>>> my_first_variable = 1 #<-- my_first_variable bound to an integer object of value one. +>>> my_first_variable = 2 #<-- my_first_variable re-assigned to integer value 2. + +>>> print(type(my_first_variable)) + + +>>> print(my_first_variable) +2 + +>>> my_first_variable = "Now, I'm a string." #<-- You may re-bind a name to a different object type and value. +>>> print(type(my_first_variable)) + + +>>> print(my_first_variable) +"Now, I'm a string." #<-- Strings can be declared using single or double quote marks. +``` + + +### Constants + +Constants are names meant to be assigned only once in a program. +They should be defined at a [module][module] (file) level, and are typically visible to all functions and classes in the program. +Using `SCREAMING_SNAKE_CASE` signals that the name should not be re-assigned, or its value mutated. + + +## Functions + +The `def` keyword begins a [function definition][function definition]. +Each function can have zero or more formal [parameters][parameters] in `()` parenthesis, followed by a `:` colon. +Statements for the _body_ of the function begin on the line following `def` and must be _indented in a block_. + + +```python +# The body of a function is indented by 2 spaces, & prints the sum of the numbers. +def add_two_numbers(number_one, number_two): + total = number_one + number_two + print(total) + +>>> add_two_numbers(3, 4) +7 + + +# Inconsistent indentation in your code blocks will raise an error. +>>> def add_three_numbers_misformatted(number_one, number_two, number_three): +... result = number_one + number_two + number_three # This was indented by 4 spaces. +... print(result) #this was only indented by 3 spaces +... +... + File "", line 3 + print(result) + ^ +IndentationError: unindent does not match any outer indentation level +``` + + +Functions _explicitly_ return a value or object via the [`return`][return] keyword: + + +```python +# Function definition on first line, explicit return used on final line. +>>> def add_two_numbers(number_one, number_two): + return number_one + number_two + + +# Calling the function in the Python terminal returns the sum of the numbers. +>>> add_two_numbers(3, 4) +7 + +# Assigning the function call to a variable and printing it +# will also return the value. +>>> sum_with_return = add_two_numbers(5, 6) +>>> print(sum_with_return) +11 +``` + + +Functions that do not have an _explicit_ `return` expression will _implicitly_ return the [`None`][none] object. +This means that if you do not use `return` in a function, Python will return the `None` object for you. +The details of `None` will be covered in a later exercise. +For the purposes of this exercise and explanation, `None` is a placeholder that represents nothing, or null: + + +```python +# This function does not have an explicit return. +def add_two_numbers(number_one, number_two): + result = number_one + number_two + + +# Calling the function in the Python terminal appears +# to not return anything at all. +>>> add_two_numbers(5, 7) +>>> + + +# Using print() with the function call shows that +# the function is actually returning the **None** object. +>>> print(add_two_numbers(5, 7)) +None + + +# Assigning the function call to a variable and printing +# the variable will also show None. +>>> sum_without_return = add_two_numbers(5, 6) +>>> print(sum_without_return) +None +``` + + +### Calling Functions + +Functions are [_called_][calls] or invoked using their name followed by `()`. +Dot (`.`) notation is used for calling functions defined inside a class or module. + +```python +>>> def number_to_the_power_of(number_one, number_two): + return number_one ** number_two +... + +>>> number_to_the_power_of(3,3) # Invoking the function with the arguments 3 and 3. +27 + + +# A mismatch between the number of parameters and the number of arguments will raise an error. +>>> number_to_the_power_of(4,) +... +Traceback (most recent call last): + File "", line 1, in +TypeError: number_to_the_power_of() missing 1 required positional argument: 'number_two' + + +# Calling methods or functions in classes and modules. +>>> start_text = "my silly sentence for examples." +>>> str.upper(start_text) # Calling the upper() method for the built-in str class. +"MY SILLY SENTENCE FOR EXAMPLES." + +# Importing the math module +import math + +>>> math.pow(2,4) # Calling the pow() function from the math module +>>> 16.0 +``` + + +## Comments + +[Comments][comments] in Python start with a `#` that is not part of a string, and end at line termination. +Unlike many other programming languages, Python **does not support** multi-line comment marks. +Each line of a comment block must start with the `#` character. + + +## Docstrings + +The first statement of a function body can optionally be a [_docstring_][docstring], which concisely summarizes the function or object's purpose. +Docstrings are declared using triple double quotes (""") indented at the same level as the code block: + + +```python + +# An example from PEP257 of a multi-line docstring. +def complex(real=0.0, imag=0.0): + """Form a complex number. + + Keyword arguments: + real -- the real part (default 0.0) + imag -- the imaginary part (default 0.0) + """ + + if imag == 0.0 and real == 0.0: + return complex_zero + +``` + + +Docstrings are read by automated documentation tools and are returned by calling the special attribute `.__doc__` on the function, method, or class name. +Docstring conventions are laid out in [PEP257][pep257]. + +Docstrings can also function as [lightweight unit tests][doctests], which will be covered in a later exercise. + + +```python +# An example on a user-defined function. +>>> def number_to_the_power_of(number_one, number_two): + """Raise a number to an arbitrary power. + + :param number_one: int the base number. + :param number_two: int the power to raise the base number to. + :return: int - number raised to power of second number + + Takes number_one and raises it to the power of number_two, returning the result. + """ + + return number_one ** number_two +... + +# Calling the .__doc__ attribute of the function and printing the result. +>>> print(number_to_the_power_of.__doc__) +Raise a number to an arbitrary power. + + :param number_one: int the base number. + :param number_two: int the power to raise the base number to. + :return: int - number raised to power of second number + + Takes number_one and raises it to the power of number_two, returning the result. +``` + +[calls]: https://docs.python.org/3/reference/expressions.html#calls +[comments]: https://realpython.com/python-comments-guide/#python-commenting-basics +[docstring]: https://docs.python.org/3/tutorial/controlflow.html#tut-docstrings +[doctests]: https://docs.python.org/3/library/doctest.html +[duck typing]: https://en.wikipedia.org/wiki/Duck_typing +[dynamic typing in python]: https://stackoverflow.com/questions/11328920/is-python-strongly-typed +[everythings an object]: https://docs.python.org/3/reference/datamodel.html +[facts-and-myths-about-python-names]: https://nedbatchelder.com/text/names.html +[function definition]: https://docs.python.org/3/tutorial/controlflow.html#defining-functions +[gradual typing]: https://en.wikipedia.org/wiki/Gradual_typing +[module]: https://docs.python.org/3/tutorial/modules.html +[none]: https://docs.python.org/3/library/constants.html +[parameters]: https://docs.python.org/3/glossary.html#term-parameter +[pep257]: https://www.python.org/dev/peps/pep-0257/ +[return]: https://docs.python.org/3/reference/simple_stmts.html#return +[type hints]: https://docs.python.org/3/library/typing.html + +## Instructions + +You're going to write some code to help you cook a gorgeous lasagna from your favorite cookbook. + +You have five tasks, all related to cooking your recipe. + +
+ +~~~~exercism/note +We have started the first function definition for you in the stub file, but you will need to write the remaining function definitions yourself. +You will also need to define any constants yourself. +Read the #TODO comment lines in the stub file carefully. +Once you are done with a task, remove the TODO comment. +~~~~ + +
+ +## 1. Define expected bake time in minutes as a constant + +Define the `EXPECTED_BAKE_TIME` [constant][constants] that represents how many minutes the lasagna should bake in the oven. +According to your cookbook, the Lasagna should be in the oven for 40 minutes: + +```python +>>> print(EXPECTED_BAKE_TIME) +40 +``` + +## 2. Calculate remaining bake time in minutes + +Complete the `bake_time_remaining()` function that takes the actual minutes the lasagna has been in the oven as an argument and returns how many minutes the lasagna still needs to bake based on the `EXPECTED_BAKE_TIME` constant. + +```python +>>> bake_time_remaining(30) +10 +``` + + +## 3. Calculate preparation time in minutes + +Define the `preparation_time_in_minutes()` [function][functions] that takes the `number_of_layers` you want to add to the lasagna as an argument and returns how many minutes you would spend making them. +Assume each layer takes 2 minutes to prepare. + +```python +>>> def preparation_time_in_minutes(number_of_layers): + ... + ... + +>>> preparation_time_in_minutes(2) +4 +``` + + +## 4. Calculate total elapsed cooking time (prep + bake) in minutes + +Define the `elapsed_time_in_minutes()` function that takes two parameters as arguments: `number_of_layers` (_the number of layers added to the lasagna_) and `elapsed_bake_time` (_the number of minutes the lasagna has been baking in the oven_). +This function should return the total number of minutes you have been cooking, or the sum of your preparation time and the time the lasagna has already spent baking in the oven. + +```python +>>> def elapsed_time_in_minutes(number_of_layers, elapsed_bake_time): + ... + ... + +>>> elapsed_time_in_minutes(3, 20) +26 +``` + + +## 5. Update the recipe with notes + +Go back through the recipe, adding "notes" in the form of [function docstrings][function-docstrings]. + +```python +def elapsed_time_in_minutes(number_of_layers, elapsed_bake_time): + """Calculate the elapsed cooking time. + + :param number_of_layers: int - the number of layers in the lasagna. + :param elapsed_bake_time: int - elapsed cooking time. + :return: int - total time elapsed (in minutes) preparing and cooking. + + This function takes two integers representing the number of lasagna layers and the + time already spent baking and calculates the total elapsed minutes spent cooking the + lasagna. + """ +``` + +[constants]: https://stackoverflow.com/a/2682752 +[functions]: https://docs.python.org/3/tutorial/controlflow.html#defining-functions +[function-docstrings]: https://docs.python.org/3/tutorial/controlflow.html#documentation-strings + +## Source + +### Created by + +- @BethanyG \ No newline at end of file diff --git a/python/guidos-gorgeous-lasagna/__pycache__/lasagna.cpython-313.pyc b/python/guidos-gorgeous-lasagna/__pycache__/lasagna.cpython-313.pyc new file mode 100644 index 0000000..24c09a7 Binary files /dev/null and b/python/guidos-gorgeous-lasagna/__pycache__/lasagna.cpython-313.pyc differ diff --git a/python/guidos-gorgeous-lasagna/__pycache__/lasagna.cpython-314.pyc b/python/guidos-gorgeous-lasagna/__pycache__/lasagna.cpython-314.pyc new file mode 100644 index 0000000..6208ee8 Binary files /dev/null and b/python/guidos-gorgeous-lasagna/__pycache__/lasagna.cpython-314.pyc differ diff --git a/python/guidos-gorgeous-lasagna/__pycache__/lasagna_test.cpython-313-pytest-8.3.4.pyc b/python/guidos-gorgeous-lasagna/__pycache__/lasagna_test.cpython-313-pytest-8.3.4.pyc new file mode 100644 index 0000000..b6a2c55 Binary files /dev/null and b/python/guidos-gorgeous-lasagna/__pycache__/lasagna_test.cpython-313-pytest-8.3.4.pyc differ diff --git a/python/guidos-gorgeous-lasagna/__pycache__/lasagna_test.cpython-314-pytest-9.1.0.pyc b/python/guidos-gorgeous-lasagna/__pycache__/lasagna_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..4889555 Binary files /dev/null and b/python/guidos-gorgeous-lasagna/__pycache__/lasagna_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/guidos-gorgeous-lasagna/lasagna.py b/python/guidos-gorgeous-lasagna/lasagna.py new file mode 100644 index 0000000..46c8340 --- /dev/null +++ b/python/guidos-gorgeous-lasagna/lasagna.py @@ -0,0 +1,67 @@ +"""Functions used in preparing Guido's gorgeous lasagna. + +Learn about Guido, the creator of the Python language: +https://en.wikipedia.org/wiki/Guido_van_Rossum + +This is a module docstring, used to describe the functionality +of a module and its functions and/or classes. +""" + +# TODO: define the 'EXPECTED_BAKE_TIME' constant below. +EXPECTED_BAKE_TIME = 40 +PREPARATION_TIME = 2 + +# TODO: Remove 'pass' and complete the 'bake_time_remaining()' function below. + + +def bake_time_remaining(elapsed_bake_time: int) -> int: + """Calculate the bake time remaining. + + :param elapsed_bake_time: int - baking time already elapsed. + :return: int - remaining bake time (in minutes) derived from 'EXPECTED_BAKE_TIME'. + + Function that takes the actual minutes the lasagna has been in the oven as + an argument and returns how many minutes the lasagna still needs to bake + based on the `EXPECTED_BAKE_TIME`. + """ + return EXPECTED_BAKE_TIME - elapsed_bake_time + + +# TODO: Define the 'preparation_time_in_minutes()' function below. +# You might also consider defining a 'PREPARATION_TIME' constant. +# You can do that on the line below the 'EXPECTED_BAKE_TIME' constant. +# This will make it easier to do calculations. +def preparation_time_in_minutes(number_of_layers: int) -> int: + """Calculate how long will take in minutes to prepare a lasagna with + number_of_layers + + :param number_of_layers: int - number of layers in the lasagna + :return int - time to make (in minutes) a lasagna with number_of_layers + + Function that takes the number_of_layers you want to add to the lasagna as + an argument and returns how many minutes you would spend making them. + Assume each layer takes 2 minutes to prepare. + """ + return number_of_layers * PREPARATION_TIME + + +# TODO: define the 'elapsed_time_in_minutes()' function below. +def elapsed_time_in_minutes(number_of_layers: int, elapsed_bake_time: int) -> int: + """Calculate the total number of minutes you have been cooking (or the sum + of your preparation time and the time the lasagna has already spent baking + in the oven). + + :param number_of_layers: int - the number of layers added to the lasagna + :param elapsed_bake_time: int - the number of minutes the lasagna has been baking in the oven + :return: int - total number of minutes you have been cooking + + Function that takes two parameters as arguments: number_of_layers (you want + to add to the lasagna) and elapsed_bake_time (number of minutes the lasagna + has been baking in the oven). This function returns the total number of + minutes you have been cooking + """ + return preparation_time_in_minutes(number_of_layers) + elapsed_bake_time + + +# TODO: Remember to go back and add docstrings to all your functions +# (you can copy and then alter the one from bake_time_remaining.) diff --git a/python/guidos-gorgeous-lasagna/lasagna_test.py b/python/guidos-gorgeous-lasagna/lasagna_test.py new file mode 100644 index 0000000..4066aa8 --- /dev/null +++ b/python/guidos-gorgeous-lasagna/lasagna_test.py @@ -0,0 +1,97 @@ +import unittest +import pytest + +# For this first exercise, it is really important to be clear about how we are importing names for tests. +# To that end, we are putting a try/catch around imports and throwing specific messages to help students +# decode that they need to create and title their constants and functions in a specific way. +try: + from lasagna import (EXPECTED_BAKE_TIME, + bake_time_remaining, + preparation_time_in_minutes, + elapsed_time_in_minutes) + +# Here, we are separating the constant import errors from the function name import errors +except ImportError as import_fail: + message = import_fail.args[0].split('(', maxsplit=1) + item_name = import_fail.args[0].split()[3] + + if 'EXPECTED_BAKE_TIME' in item_name: + # pylint: disable=raise-missing-from + raise ImportError(f'\n\nMISSING CONSTANT --> \nWe can not find or import the constant {item_name} in your' + " 'lasagna.py' file.\nDid you misname or forget to define it?") from None + else: + item_name = item_name[:-1] + "()'" + # pylint: disable=raise-missing-from + raise ImportError("\n\nMISSING FUNCTION --> In your 'lasagna.py' file, we can not find or import the" + f' function named {item_name}. \nDid you misname or forget to define it?') from None + + +# Here begins the formal test cases for the exercise. +class LasagnaTest(unittest.TestCase): + + @pytest.mark.task(taskno=1) + def test_EXPECTED_BAKE_TIME(self): + failure_msg = 'Expected a constant of EXPECTED_BAKE_TIME with a value of 40.' + self.assertEqual(EXPECTED_BAKE_TIME, 40, msg=failure_msg) + + @pytest.mark.task(taskno=2) + def test_bake_time_remaining(self): + input_data = [1, 2, 5, 10, 15, 23, 33, 39] + result_data = [39, 38, 35, 30, 25, 17, 7, 1] + + for variant, (time, expected) in enumerate(zip(input_data, result_data), start=1): + with self.subTest(f'variation #{variant}', time=time, expected=expected): + actual_result = bake_time_remaining(time) + failure_msg = (f'Called bake_time_remaining({time}). ' + f'The function returned {actual_result}, but the tests ' + f'expected {expected} as the remaining bake time.') + + self.assertEqual(actual_result, expected, msg=failure_msg) + + @pytest.mark.task(taskno=3) + def test_preparation_time_in_minutes(self): + input_data = [1, 2, 5, 8, 11, 15] + result_data = [2, 4, 10, 16, 22, 30] + + for variant, (layers, expected) in enumerate(zip(input_data, result_data), start=1): + with self.subTest(f'variation #{variant}', layers=layers, expected=expected): + actual_result = preparation_time_in_minutes(layers) + failure_msg = (f'Called preparation_time_in_minutes({layers}). ' + f'The function returned {actual_result}, but the tests ' + f'expected {expected} as the preparation time.') + + self.assertEqual(actual_result, expected, msg=failure_msg) + + @pytest.mark.task(taskno=4) + def test_elapsed_time_in_minutes(self): + layer_data = (1, 2, 5, 8, 11, 15) + time_data = (3, 7, 8, 4, 15, 20) + result_data = [5, 11, 18, 20, 37, 50] + + for variant, (layers, time, expected) in enumerate(zip(layer_data, time_data, result_data), start=1): + with self.subTest(f'variation #{variant}', layers=layers, time=time, expected=expected): + actual_result = elapsed_time_in_minutes(layers, time) + failure_msg = (f'Called elapsed_time_in_minutes({layers}, {time}). ' + f'The function returned {actual_result}, but the tests ' + f'expected {expected} as the elapsed time.') + + self.assertEqual(actual_result, expected, msg=failure_msg) + + @pytest.mark.task(taskno=5) + def test_docstrings_were_written(self): + """Validate function.__doc__ exists for each function. + Check the attribute dictionary of each listed function + for the presence of a __doc__ key. + + :return: unexpectedly None error when __doc__ key is missing. + """ + functions = [bake_time_remaining, preparation_time_in_minutes, elapsed_time_in_minutes] + + for variant, function in enumerate(functions, start=1): + with self.subTest(f'variation #{variant}', function=function): + actual_result = function.__doc__ + failure_msg = (f'Called {function.__name__}.__doc__. {actual_result} was returned, ' + f'but the tests expected a docstring for the {function.__name__} function.') + + # Check that the __doc__ key is populated for the function. + self.assertIsNotNone(actual_result, msg=failure_msg) diff --git a/python/hamming/.exercism/config.json b/python/hamming/.exercism/config.json new file mode 100644 index 0000000..117a2d9 --- /dev/null +++ b/python/hamming/.exercism/config.json @@ -0,0 +1,37 @@ +{ + "authors": [ + "betegelse" + ], + "contributors": [ + "behrtam", + "cmccandless", + "Dog", + "gabriel376", + "GascaK", + "guaneec", + "iandexter", + "ikhadykin", + "kytrinyx", + "N-Parsons", + "parthsharma2", + "pheanex", + "pywkm", + "sjakobi", + "tqa236", + "yawpitch" + ], + "files": { + "solution": [ + "hamming.py" + ], + "test": [ + "hamming_test.py" + ], + "example": [ + ".meta/example.py" + ] + }, + "blurb": "Calculate the Hamming distance between two DNA strands.", + "source": "The Calculating Point Mutations problem at Rosalind", + "source_url": "https://rosalind.info/problems/hamm/" +} diff --git a/python/hamming/.exercism/metadata.json b/python/hamming/.exercism/metadata.json new file mode 100644 index 0000000..266e733 --- /dev/null +++ b/python/hamming/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"hamming","id":"8a66b2150867460faacda56cd2ee2127","url":"https://exercism.org/tracks/python/exercises/hamming","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/hamming/HELP.md b/python/hamming/HELP.md new file mode 100644 index 0000000..b26b226 --- /dev/null +++ b/python/hamming/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +
+ +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit hamming.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/hamming/README.md b/python/hamming/README.md new file mode 100644 index 0000000..15c6087 --- /dev/null +++ b/python/hamming/README.md @@ -0,0 +1,76 @@ +# Hamming + +Welcome to Hamming on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Introduction + +Your body is made up of cells that contain DNA. +Those cells regularly wear out and need replacing, which they achieve by dividing into daughter cells. +In fact, the average human body experiences about 10 quadrillion cell divisions in a lifetime! + +When cells divide, their DNA replicates too. +Sometimes during this process mistakes happen and single pieces of DNA get encoded with the incorrect information. +If we compare two strands of DNA and count the differences between them, we can see how many mistakes occurred. +This is known as the "Hamming distance". + +The Hamming distance is useful in many areas of science, not just biology, so it's a nice phrase to be familiar with :) + +## Instructions + +Calculate the Hamming distance between two DNA strands. + +We read DNA using the letters C, A, G and T. +Two strands might look like this: + + GAGCCTACTAACGGGAT + CATCGTAATGACGGCCT + ^ ^ ^ ^ ^ ^^ + +They have 7 differences, and therefore the Hamming distance is 7. + +## Implementation notes + +The Hamming distance is only defined for sequences of equal length, so an attempt to calculate it between sequences of different lengths should not work. + +## Exception messages + +Sometimes it is necessary to [raise an exception](https://docs.python.org/3/tutorial/errors.html#raising-exceptions). When you do this, you should always include a **meaningful error message** to indicate what the source of the error is. This makes your code more readable and helps significantly with debugging. For situations where you know that the error source will be a certain type, you can choose to raise one of the [built in error types](https://docs.python.org/3/library/exceptions.html#base-classes), but should still include a meaningful message. + +This particular exercise requires that you use the [raise statement](https://docs.python.org/3/reference/simple_stmts.html#the-raise-statement) to "throw" a `ValueError` when the strands being checked are not the same length. The tests will only pass if you both `raise` the `exception` and include a message with it. + +To raise a `ValueError` with a message, write the message as an argument to the `exception` type: + +```python +# When the sequences being passed are not the same length. +raise ValueError("Strands must be of equal length.") +``` + +## Source + +### Created by + +- @betegelse + +### Contributed to by + +- @behrtam +- @cmccandless +- @Dog +- @gabriel376 +- @GascaK +- @guaneec +- @iandexter +- @ikhadykin +- @kytrinyx +- @N-Parsons +- @parthsharma2 +- @pheanex +- @pywkm +- @sjakobi +- @tqa236 +- @yawpitch + +### Based on + +The Calculating Point Mutations problem at Rosalind - https://rosalind.info/problems/hamm/ \ No newline at end of file diff --git a/python/hamming/__pycache__/hamming.cpython-313.pyc b/python/hamming/__pycache__/hamming.cpython-313.pyc new file mode 100644 index 0000000..95236e8 Binary files /dev/null and b/python/hamming/__pycache__/hamming.cpython-313.pyc differ diff --git a/python/hamming/__pycache__/hamming.cpython-314.pyc b/python/hamming/__pycache__/hamming.cpython-314.pyc new file mode 100644 index 0000000..4cd30a6 Binary files /dev/null and b/python/hamming/__pycache__/hamming.cpython-314.pyc differ diff --git a/python/hamming/__pycache__/hamming_test.cpython-313-pytest-8.3.5.pyc b/python/hamming/__pycache__/hamming_test.cpython-313-pytest-8.3.5.pyc new file mode 100644 index 0000000..daefbdf Binary files /dev/null and b/python/hamming/__pycache__/hamming_test.cpython-313-pytest-8.3.5.pyc differ diff --git a/python/hamming/__pycache__/hamming_test.cpython-314-pytest-9.1.0.pyc b/python/hamming/__pycache__/hamming_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..35dec2c Binary files /dev/null and b/python/hamming/__pycache__/hamming_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/hamming/hamming.py b/python/hamming/hamming.py new file mode 100644 index 0000000..174cdbb --- /dev/null +++ b/python/hamming/hamming.py @@ -0,0 +1,8 @@ +def distance(strand_a, strand_b): + hamming_distance: int = 0 + if len(strand_a) != len(strand_b): + raise ValueError("Strands must be of equal length.") + for index in range(len(strand_a)): + if strand_a[index] != strand_b[index]: + hamming_distance += 1 + return hamming_distance diff --git a/python/hamming/hamming_test.py b/python/hamming/hamming_test.py new file mode 100644 index 0000000..df58ef0 --- /dev/null +++ b/python/hamming/hamming_test.py @@ -0,0 +1,54 @@ +# These tests are auto-generated with test data from: +# https://github.com/exercism/problem-specifications/tree/main/exercises/hamming/canonical-data.json +# File last updated on 2023-07-19 + +import unittest + +from hamming import ( + distance, +) + + +class HammingTest(unittest.TestCase): + def test_empty_strands(self): + self.assertEqual(distance("", ""), 0) + + def test_single_letter_identical_strands(self): + self.assertEqual(distance("A", "A"), 0) + + def test_single_letter_different_strands(self): + self.assertEqual(distance("G", "T"), 1) + + def test_long_identical_strands(self): + self.assertEqual(distance("GGACTGAAATCTG", "GGACTGAAATCTG"), 0) + + def test_long_different_strands(self): + self.assertEqual(distance("GGACGGATTCTG", "AGGACGGATTCT"), 9) + + def test_disallow_first_strand_longer(self): + with self.assertRaises(ValueError) as err: + distance("AATG", "AAA") + + self.assertEqual(type(err.exception), ValueError) + self.assertEqual(err.exception.args[0], "Strands must be of equal length.") + + def test_disallow_second_strand_longer(self): + with self.assertRaises(ValueError) as err: + distance("ATA", "AGTG") + + self.assertEqual(type(err.exception), ValueError) + self.assertEqual(err.exception.args[0], "Strands must be of equal length.") + + def test_disallow_empty_first_strand(self): + with self.assertRaises(ValueError) as err: + distance("", "G") + + self.assertEqual(type(err.exception), ValueError) + self.assertEqual(err.exception.args[0], "Strands must be of equal length.") + + def test_disallow_empty_second_strand(self): + with self.assertRaises(ValueError) as err: + distance("G", "") + + self.assertEqual(type(err.exception), ValueError) + self.assertEqual(err.exception.args[0], "Strands must be of equal length.") diff --git a/python/hello-world/.exercism/config.json b/python/hello-world/.exercism/config.json new file mode 100644 index 0000000..16a87cf --- /dev/null +++ b/python/hello-world/.exercism/config.json @@ -0,0 +1,33 @@ +{ + "authors": [ + "michaelem" + ], + "contributors": [ + "behrtam", + "cmccandless", + "Dog", + "hebertjulio", + "ikhadykin", + "kytrinyx", + "N-Parsons", + "NobbZ", + "pheanex", + "skeskali", + "Sukhj1nder", + "tqa236" + ], + "files": { + "solution": [ + "hello_world.py" + ], + "test": [ + "hello_world_test.py" + ], + "example": [ + ".meta/example.py" + ] + }, + "blurb": "Exercism's classic introductory exercise. Just say \"Hello, World!\".", + "source": "This is an exercise to introduce users to using Exercism", + "source_url": "https://en.wikipedia.org/wiki/%22Hello,_world!%22_program" +} diff --git a/python/hello-world/.exercism/metadata.json b/python/hello-world/.exercism/metadata.json new file mode 100644 index 0000000..5c9f7f1 --- /dev/null +++ b/python/hello-world/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"hello-world","id":"d4975d7b22b143b0b3b6e79edf8ffc0e","url":"https://exercism.org/tracks/python/exercises/hello-world","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/hello-world/HELP.md b/python/hello-world/HELP.md new file mode 100644 index 0000000..d691b37 --- /dev/null +++ b/python/hello-world/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +
+ +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit hello_world.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/hello-world/README.md b/python/hello-world/README.md new file mode 100644 index 0000000..a24a454 --- /dev/null +++ b/python/hello-world/README.md @@ -0,0 +1,46 @@ +# Hello World + +Welcome to Hello World on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Instructions + +The classical introductory exercise. +Just say "Hello, World!". + +["Hello, World!"][hello-world] is the traditional first program for beginning programming in a new language or environment. + +The objectives are simple: + +- Modify the provided code so that it produces the string "Hello, World!". +- Run the test suite and make sure that it succeeds. +- Submit your solution and check it at the website. + +If everything goes well, you will be ready to fetch your first real exercise. + +[hello-world]: https://en.wikipedia.org/wiki/%22Hello,_world!%22_program + +## Source + +### Created by + +- @michaelem + +### Contributed to by + +- @behrtam +- @cmccandless +- @Dog +- @hebertjulio +- @ikhadykin +- @kytrinyx +- @N-Parsons +- @NobbZ +- @pheanex +- @skeskali +- @Sukhj1nder +- @tqa236 + +### Based on + +This is an exercise to introduce users to using Exercism - https://en.wikipedia.org/wiki/%22Hello,_world!%22_program \ No newline at end of file diff --git a/python/hello-world/__pycache__/hello_world.cpython-313.pyc b/python/hello-world/__pycache__/hello_world.cpython-313.pyc new file mode 100644 index 0000000..0678682 Binary files /dev/null and b/python/hello-world/__pycache__/hello_world.cpython-313.pyc differ diff --git a/python/hello-world/__pycache__/hello_world.cpython-314.pyc b/python/hello-world/__pycache__/hello_world.cpython-314.pyc new file mode 100644 index 0000000..488606a Binary files /dev/null and b/python/hello-world/__pycache__/hello_world.cpython-314.pyc differ diff --git a/python/hello-world/__pycache__/hello_world_test.cpython-313-pytest-8.3.4.pyc b/python/hello-world/__pycache__/hello_world_test.cpython-313-pytest-8.3.4.pyc new file mode 100644 index 0000000..95a8b8e Binary files /dev/null and b/python/hello-world/__pycache__/hello_world_test.cpython-313-pytest-8.3.4.pyc differ diff --git a/python/hello-world/__pycache__/hello_world_test.cpython-314-pytest-9.1.0.pyc b/python/hello-world/__pycache__/hello_world_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..b5bdd02 Binary files /dev/null and b/python/hello-world/__pycache__/hello_world_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/hello-world/hello_world.py b/python/hello-world/hello_world.py new file mode 100644 index 0000000..dea05ae --- /dev/null +++ b/python/hello-world/hello_world.py @@ -0,0 +1,2 @@ +def hello(): + return "Hello, World!" diff --git a/python/hello-world/hello_world_test.py b/python/hello-world/hello_world_test.py new file mode 100644 index 0000000..15473f5 --- /dev/null +++ b/python/hello-world/hello_world_test.py @@ -0,0 +1,30 @@ +# These tests are auto-generated with test data from: +# https://github.com/exercism/problem-specifications/tree/main/exercises/hello-world/canonical-data.json +# File last updated on 2023-07-19 + +import unittest + +try: + from hello_world import ( + hello, + ) + +except ImportError as import_fail: + message = import_fail.args[0].split("(", maxsplit=1) + item_name = import_fail.args[0].split()[3] + + item_name = item_name[:-1] + "()'" + + # pylint: disable=raise-missing-from + raise ImportError( + "\n\nMISSING FUNCTION --> In your 'hello_world.py' file, we can not find or import the" + f" function named {item_name}. \nThe tests for this first exercise expect a function that" + f' returns the string "Hello, World!"' + f'\n\nDid you use print("Hello, World!") instead?' + ) from None + + +class HelloWorldTest(unittest.TestCase): + def test_say_hi(self): + msg = "\n\nThis test expects a return of the string 'Hello, World!' \nDid you use print('Hello, World!') by mistake?" + self.assertEqual(hello(), "Hello, World!", msg=msg) diff --git a/python/house/.exercism/config.json b/python/house/.exercism/config.json new file mode 100644 index 0000000..328c8c9 --- /dev/null +++ b/python/house/.exercism/config.json @@ -0,0 +1,31 @@ +{ + "authors": [ + "betegelse" + ], + "contributors": [ + "behrtam", + "cmccandless", + "Dog", + "dvermd", + "kytrinyx", + "MartinDelille", + "N-Parsons", + "pheanex", + "sjakobi", + "tqa236" + ], + "files": { + "solution": [ + "house.py" + ], + "test": [ + "house_test.py" + ], + "example": [ + ".meta/example.py" + ] + }, + "blurb": "Output the nursery rhyme 'This is the House that Jack Built'.", + "source": "British nursery rhyme", + "source_url": "https://en.wikipedia.org/wiki/This_Is_The_House_That_Jack_Built" +} diff --git a/python/house/.exercism/metadata.json b/python/house/.exercism/metadata.json new file mode 100644 index 0000000..bfb56ed --- /dev/null +++ b/python/house/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"house","id":"b2f625149bf14120a2e9febecd208e3e","url":"https://exercism.org/tracks/python/exercises/house","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/house/HELP.md b/python/house/HELP.md new file mode 100644 index 0000000..7104f03 --- /dev/null +++ b/python/house/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +
+ +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit house.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/house/README.md b/python/house/README.md new file mode 100644 index 0000000..9cc515d --- /dev/null +++ b/python/house/README.md @@ -0,0 +1,133 @@ +# House + +Welcome to House on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Instructions + +Recite the nursery rhyme 'This is the House that Jack Built'. + +> [The] process of placing a phrase of clause within another phrase of clause is called embedding. +> It is through the processes of recursion and embedding that we are able to take a finite number of forms (words and phrases) and construct an infinite number of expressions. +> Furthermore, embedding also allows us to construct an infinitely long structure, in theory anyway. + +- [papyr.com][papyr] + +The nursery rhyme reads as follows: + +```text +This is the house that Jack built. + +This is the malt +that lay in the house that Jack built. + +This is the rat +that ate the malt +that lay in the house that Jack built. + +This is the cat +that killed the rat +that ate the malt +that lay in the house that Jack built. + +This is the dog +that worried the cat +that killed the rat +that ate the malt +that lay in the house that Jack built. + +This is the cow with the crumpled horn +that tossed the dog +that worried the cat +that killed the rat +that ate the malt +that lay in the house that Jack built. + +This is the maiden all forlorn +that milked the cow with the crumpled horn +that tossed the dog +that worried the cat +that killed the rat +that ate the malt +that lay in the house that Jack built. + +This is the man all tattered and torn +that kissed the maiden all forlorn +that milked the cow with the crumpled horn +that tossed the dog +that worried the cat +that killed the rat +that ate the malt +that lay in the house that Jack built. + +This is the priest all shaven and shorn +that married the man all tattered and torn +that kissed the maiden all forlorn +that milked the cow with the crumpled horn +that tossed the dog +that worried the cat +that killed the rat +that ate the malt +that lay in the house that Jack built. + +This is the rooster that crowed in the morn +that woke the priest all shaven and shorn +that married the man all tattered and torn +that kissed the maiden all forlorn +that milked the cow with the crumpled horn +that tossed the dog +that worried the cat +that killed the rat +that ate the malt +that lay in the house that Jack built. + +This is the farmer sowing his corn +that kept the rooster that crowed in the morn +that woke the priest all shaven and shorn +that married the man all tattered and torn +that kissed the maiden all forlorn +that milked the cow with the crumpled horn +that tossed the dog +that worried the cat +that killed the rat +that ate the malt +that lay in the house that Jack built. + +This is the horse and the hound and the horn +that belonged to the farmer sowing his corn +that kept the rooster that crowed in the morn +that woke the priest all shaven and shorn +that married the man all tattered and torn +that kissed the maiden all forlorn +that milked the cow with the crumpled horn +that tossed the dog +that worried the cat +that killed the rat +that ate the malt +that lay in the house that Jack built. +``` + +[papyr]: https://papyr.com/hypertextbooks/grammar/ph_noun.htm + +## Source + +### Created by + +- @betegelse + +### Contributed to by + +- @behrtam +- @cmccandless +- @Dog +- @dvermd +- @kytrinyx +- @MartinDelille +- @N-Parsons +- @pheanex +- @sjakobi +- @tqa236 + +### Based on + +British nursery rhyme - https://en.wikipedia.org/wiki/This_Is_The_House_That_Jack_Built \ No newline at end of file diff --git a/python/house/__pycache__/house.cpython-313.pyc b/python/house/__pycache__/house.cpython-313.pyc new file mode 100644 index 0000000..088f2d5 Binary files /dev/null and b/python/house/__pycache__/house.cpython-313.pyc differ diff --git a/python/house/__pycache__/house.cpython-314.pyc b/python/house/__pycache__/house.cpython-314.pyc new file mode 100644 index 0000000..6cf4dc2 Binary files /dev/null and b/python/house/__pycache__/house.cpython-314.pyc differ diff --git a/python/house/__pycache__/house_test.cpython-313-pytest-8.3.4.pyc b/python/house/__pycache__/house_test.cpython-313-pytest-8.3.4.pyc new file mode 100644 index 0000000..11d11e5 Binary files /dev/null and b/python/house/__pycache__/house_test.cpython-313-pytest-8.3.4.pyc differ diff --git a/python/house/__pycache__/house_test.cpython-314-pytest-9.1.0.pyc b/python/house/__pycache__/house_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..ea8b518 Binary files /dev/null and b/python/house/__pycache__/house_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/house/house.py b/python/house/house.py new file mode 100644 index 0000000..9520523 --- /dev/null +++ b/python/house/house.py @@ -0,0 +1,24 @@ +def recite(start_verse, end_verse): + appendices_list: list[str] = [ + "the house that Jack built.", + "the malt that lay in", + "the rat that ate", + "the cat that killed", + "the dog that worried", + "the cow with the crumpled horn that tossed", + "the maiden all forlorn that milked", + "the man all tattered and torn that kissed", + "the priest all shaven and shorn that married", + "the rooster that crowed in the morn that woke", + "the farmer sowing his corn that kept", + "the horse and the hound and the horn that belonged to", + ] + verses_to_recite: list[str] = [] + for verse_id in range(start_verse - 1, end_verse): + current_verse: list = ["This is"] + for part in range(verse_id, -1, -1): + current_verse.append(appendices_list[part]) + verses_to_recite.append(" ".join(current_verse)) + current_verse.clear() + print(verses_to_recite) + return verses_to_recite diff --git a/python/house/house_test.py b/python/house/house_test.py new file mode 100644 index 0000000..d859fb4 --- /dev/null +++ b/python/house/house_test.py @@ -0,0 +1,130 @@ +# These tests are auto-generated with test data from: +# https://github.com/exercism/problem-specifications/tree/main/exercises/house/canonical-data.json +# File last updated on 2023-07-19 + +import unittest + +from house import ( + recite, +) + + +class HouseTest(unittest.TestCase): + def test_verse_one_the_house_that_jack_built(self): + self.assertEqual(recite(1, 1), ["This is the house that Jack built."]) + + def test_verse_two_the_malt_that_lay(self): + self.assertEqual( + recite(2, 2), ["This is the malt that lay in the house that Jack built."] + ) + + def test_verse_three_the_rat_that_ate(self): + self.assertEqual( + recite(3, 3), + [ + "This is the rat that ate the malt that lay in the house that Jack built." + ], + ) + + def test_verse_four_the_cat_that_killed(self): + self.assertEqual( + recite(4, 4), + [ + "This is the cat that killed the rat that ate the malt that lay in the house that Jack built." + ], + ) + + def test_verse_five_the_dog_that_worried(self): + self.assertEqual( + recite(5, 5), + [ + "This is the dog that worried the cat that killed the rat that ate the malt that lay in the house that Jack built." + ], + ) + + def test_verse_six_the_cow_with_the_crumpled_horn(self): + self.assertEqual( + recite(6, 6), + [ + "This is the cow with the crumpled horn that tossed the dog that worried the cat that killed the rat that ate the malt that lay in the house that Jack built." + ], + ) + + def test_verse_seven_the_maiden_all_forlorn(self): + self.assertEqual( + recite(7, 7), + [ + "This is the maiden all forlorn that milked the cow with the crumpled horn that tossed the dog that worried the cat that killed the rat that ate the malt that lay in the house that Jack built." + ], + ) + + def test_verse_eight_the_man_all_tattered_and_torn(self): + self.assertEqual( + recite(8, 8), + [ + "This is the man all tattered and torn that kissed the maiden all forlorn that milked the cow with the crumpled horn that tossed the dog that worried the cat that killed the rat that ate the malt that lay in the house that Jack built." + ], + ) + + def test_verse_nine_the_priest_all_shaven_and_shorn(self): + self.assertEqual( + recite(9, 9), + [ + "This is the priest all shaven and shorn that married the man all tattered and torn that kissed the maiden all forlorn that milked the cow with the crumpled horn that tossed the dog that worried the cat that killed the rat that ate the malt that lay in the house that Jack built." + ], + ) + + def test_verse_10_the_rooster_that_crowed_in_the_morn(self): + self.assertEqual( + recite(10, 10), + [ + "This is the rooster that crowed in the morn that woke the priest all shaven and shorn that married the man all tattered and torn that kissed the maiden all forlorn that milked the cow with the crumpled horn that tossed the dog that worried the cat that killed the rat that ate the malt that lay in the house that Jack built." + ], + ) + + def test_verse_11_the_farmer_sowing_his_corn(self): + self.assertEqual( + recite(11, 11), + [ + "This is the farmer sowing his corn that kept the rooster that crowed in the morn that woke the priest all shaven and shorn that married the man all tattered and torn that kissed the maiden all forlorn that milked the cow with the crumpled horn that tossed the dog that worried the cat that killed the rat that ate the malt that lay in the house that Jack built." + ], + ) + + def test_verse_12_the_horse_and_the_hound_and_the_horn(self): + self.assertEqual( + recite(12, 12), + [ + "This is the horse and the hound and the horn that belonged to the farmer sowing his corn that kept the rooster that crowed in the morn that woke the priest all shaven and shorn that married the man all tattered and torn that kissed the maiden all forlorn that milked the cow with the crumpled horn that tossed the dog that worried the cat that killed the rat that ate the malt that lay in the house that Jack built." + ], + ) + + def test_multiple_verses(self): + self.assertEqual( + recite(4, 8), + [ + "This is the cat that killed the rat that ate the malt that lay in the house that Jack built.", + "This is the dog that worried the cat that killed the rat that ate the malt that lay in the house that Jack built.", + "This is the cow with the crumpled horn that tossed the dog that worried the cat that killed the rat that ate the malt that lay in the house that Jack built.", + "This is the maiden all forlorn that milked the cow with the crumpled horn that tossed the dog that worried the cat that killed the rat that ate the malt that lay in the house that Jack built.", + "This is the man all tattered and torn that kissed the maiden all forlorn that milked the cow with the crumpled horn that tossed the dog that worried the cat that killed the rat that ate the malt that lay in the house that Jack built.", + ], + ) + + def test_full_rhyme(self): + self.assertEqual( + recite(1, 12), + [ + "This is the house that Jack built.", + "This is the malt that lay in the house that Jack built.", + "This is the rat that ate the malt that lay in the house that Jack built.", + "This is the cat that killed the rat that ate the malt that lay in the house that Jack built.", + "This is the dog that worried the cat that killed the rat that ate the malt that lay in the house that Jack built.", + "This is the cow with the crumpled horn that tossed the dog that worried the cat that killed the rat that ate the malt that lay in the house that Jack built.", + "This is the maiden all forlorn that milked the cow with the crumpled horn that tossed the dog that worried the cat that killed the rat that ate the malt that lay in the house that Jack built.", + "This is the man all tattered and torn that kissed the maiden all forlorn that milked the cow with the crumpled horn that tossed the dog that worried the cat that killed the rat that ate the malt that lay in the house that Jack built.", + "This is the priest all shaven and shorn that married the man all tattered and torn that kissed the maiden all forlorn that milked the cow with the crumpled horn that tossed the dog that worried the cat that killed the rat that ate the malt that lay in the house that Jack built.", + "This is the rooster that crowed in the morn that woke the priest all shaven and shorn that married the man all tattered and torn that kissed the maiden all forlorn that milked the cow with the crumpled horn that tossed the dog that worried the cat that killed the rat that ate the malt that lay in the house that Jack built.", + "This is the farmer sowing his corn that kept the rooster that crowed in the morn that woke the priest all shaven and shorn that married the man all tattered and torn that kissed the maiden all forlorn that milked the cow with the crumpled horn that tossed the dog that worried the cat that killed the rat that ate the malt that lay in the house that Jack built.", + "This is the horse and the hound and the horn that belonged to the farmer sowing his corn that kept the rooster that crowed in the morn that woke the priest all shaven and shorn that married the man all tattered and torn that kissed the maiden all forlorn that milked the cow with the crumpled horn that tossed the dog that worried the cat that killed the rat that ate the malt that lay in the house that Jack built.", + ], + ) diff --git a/python/inventory-management/.exercism/config.json b/python/inventory-management/.exercism/config.json new file mode 100644 index 0000000..c08624a --- /dev/null +++ b/python/inventory-management/.exercism/config.json @@ -0,0 +1,24 @@ +{ + "authors": [ + "j08k" + ], + "contributors": [ + "valentin-p", + "bethanyG", + "mukeshgurpude", + "kotp" + ], + "files": { + "solution": [ + "dicts.py" + ], + "test": [ + "dicts_test.py" + ], + "exemplar": [ + ".meta/exemplar.py" + ] + }, + "icon": "high-scores", + "blurb": "Learn about dicts by managing warehouse inventory." +} diff --git a/python/inventory-management/.exercism/metadata.json b/python/inventory-management/.exercism/metadata.json new file mode 100644 index 0000000..5aafe04 --- /dev/null +++ b/python/inventory-management/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"inventory-management","id":"cd6171c10c1d4c5c8ff039bc0d4af80f","url":"https://exercism.org/tracks/python/exercises/inventory-management","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/inventory-management/HELP.md b/python/inventory-management/HELP.md new file mode 100644 index 0000000..1f8c21d --- /dev/null +++ b/python/inventory-management/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +
+ +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit dicts.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/inventory-management/HINTS.md b/python/inventory-management/HINTS.md new file mode 100644 index 0000000..da27ec3 --- /dev/null +++ b/python/inventory-management/HINTS.md @@ -0,0 +1,49 @@ +# Hints + +## General + +- [The Python Dictionary Tutorial][dict-tutorial] can be a great place to start. +- The Python docs on [Mapping Types - dicts][dict docs] is also pretty helpful. + +## 1. Create an inventory based on a list + +- You need a [for loop][for-loop] to iterate the list of items, then insert each item in the dictionary if missing and increment the item count using the dictionary accessor. +- You can use [`dict.setdefault`][dict setdefault] to make sure the value is set before incrementing the count of the item. +- This function should [return][return-keyword] a dict]. + +## 2. Add items from a list to an existing dictionary + +- You need a [for loop][for-loop] to iterate the list of items, then insert each item if not already in the dictionary and [increment][increment] the item count using the dictionary accessor. +- You can use [`dict.setdefault`][dict setdefault] to make sure the value is set before incrementing the count of the item. +- The function `add_items` can be used by the `create_inventory` function with an empty dictionary in parameter. +- This function should [return][return-keyword] a dict. + +## 3. Decrement items from the inventory + +- You need [for loop][for-loop] to iterate the list of items, if the number of items is not `0` then [decrement][decrement] the current number of items. +- You can use the check `key in dict` that returns `True` if the key exists to make sure the value is in the dictionary before decrementing the number of items. +- This function should [return][return-keyword] a dict. + +## 4. Remove an item entirely from the inventory + +- If item is in the dictionary, [remove it][dict-pop]. +- If item is not in the dictionary, do nothing. +- This function should [return][return-keyword] a dict. + +## 5. Return the inventory content + +- You need to use a [for loop][for-loop] on the inventory and if the number of item is greater of `0` then append the `tuple` to a `list`. +- You can use [`dict.items()`][dict items] to iterate on both the item and the value at the same time, `items()` returns a `tuple` that you can use or deconstruct, if needed. +- This function should [return][return-keyword] a [list][list] of [tuples][tuples]. + +[decrement]: https://www.w3schools.com/python/gloss_python_assignment_operators.asp +[dict docs]: https://docs.python.org/3/library/stdtypes.html#mapping-types-dict +[dict items]: https://docs.python.org/3/library/stdtypes.html#dict.items +[dict setdefault]: https://www.w3schools.com/python/ref_dictionary_setdefault.asp +[dict-pop]: https://www.w3schools.com/python/ref_dictionary_pop.asp +[dict-tutorial]: https://docs.python.org/3/tutorial/datastructures.html#dictionaries +[for-loop]: https://docs.python.org/3/tutorial/controlflow.html#for-statements +[increment]: https://www.w3schools.com/python/gloss_python_assignment_operators.asp +[list]: https://docs.python.org/3/tutorial/introduction.html#lists +[return-keyword]: https://www.w3schools.com/python/ref_keyword_return.asp +[tuples]: https://docs.python.org/3/tutorial/datastructures.html#tuples-and-sequences \ No newline at end of file diff --git a/python/inventory-management/README.md b/python/inventory-management/README.md new file mode 100644 index 0000000..ea5a34f --- /dev/null +++ b/python/inventory-management/README.md @@ -0,0 +1,247 @@ +# Inventory Management + +Welcome to Inventory Management on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. +If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :) + +## Introduction + +A dictionary (`dict`) in Python is a data structure that associates [hashable][term-hashable] _keys_ to _values_ and is known in other programming languages as a resizable [hash table][hashtable-wikipedia], hashmap, or [associative array][associative-array]. +Dictionaries are Python's only built-in [mapping type][mapping-types-dict]. + + +`Keys` must be hashable and unique across the dictionary. +Key types can include `numbers`, `str`, or `tuples` (of _immutable_ values). +They cannot contain _mutable_ data structures such as `lists`, `dict`s, or `set`s. +As of Python 3.7, `dict` key order is guaranteed to be the order in which entries are inserted. + +`values` can be of any data type or structure. + Values can also nest _arbitrarily_, so they can include lists-of-lists, sub-dictionaries, and other custom or compound data structures. + +Given a `key`, dictionaries can retrieve a `value` in (on average) constant time (_independent of the number of entries_). +Compared to searching for a value within a `list` or `array` (_without knowing the `index` position_), a `dict` uses significantly more memory, but has very rapid retrieval. +Dictionaries are especially useful in scenarios where the collection of items is large and must be accessed and updated frequently. + + +## Dictionary Construction + +Dictionaries can be created in many ways. +The two most straightforward are using the `dict()`constructor or declaring a `dict` _literal_. + +### The `dict()` Class Constructor + +`dict()` (_the constructor for the dictionary class_) can be used with any iterable of `key`, `value` pairs or with a series of `=` _arguments_: + +```python +#Passing a list of key,value tuples. +>>> wombat = dict([('name', 'Wombat'),('speed', 23),('land_animal', True)]) +{'name': 'Wombat', 'speed': 23, 'land_animal': True} + + +#Using key=value arguments. +>>> bear = dict(name="Black Bear", speed=40, land_animal=True) +{'name': 'Black Bear', 'speed': 40, 'land_animal': True} +``` + +### Dictionary Literals + +A `dict` can also be directly entered as a _dictionary literal_, using curly brackets (`{}`) enclosing `key : value` pairs: + +```python +>>> whale = {"name": "Blue Whale", "speed": 35, "land_animal": False} +{'name': 'Blue Whale', 'speed': 35, 'land_animal': False} +``` + +## Accessing Values in a Dictionary + +You can access an entry in a dictionary using a _key_ in square (`[]`) brackets. +If a `key` does not exist n the `dict`, a `KeyError` is thrown: + +```python +>>> bear["speed"] +40 + +>>> bear["color"] +Traceback (most recent call last): + File "", line 1, in +KeyError: 'color' +``` + +Accessing an entry via the `.get(, )` method can avoid the `KeyError`: + +```python +>>> bear.get("color", 'not found') +'not found' +``` + +## Changing or Adding Dictionary Values + +You can change an entry `value` by assigning to its _key_: + +```python +#Assigning the value "Grizzly Bear" to the name key. +>>> bear["name"] = "Grizzly Bear" +{'name': 'Grizzly Bear', 'speed': 40, 'land_animal': True} + +>>> whale["speed"] = 25 +{'name': 'Blue Whale', 'speed': 25, 'land_animal': False} +``` + +New `key`:`value` pairs can be _added_ in the same fashion: + +```python +# Adding an new "color" key with a new "tawney" value. +>>> bear["color"] = 'tawney' +{'name': 'Grizzly Bear', 'speed': 40, 'land_animal': True, 'color': 'tawney'} + +>>> whale["blowholes"] = 1 +{'name': 'Blue Whale', 'speed': 25, 'land_animal': False, 'blowholes': 1} +``` + +## Removing (Pop-ing) Dictionary Entries + +You can use the `.pop()` method to delete a dictionary entry. +`.pop()` removes the (`key`, `value`) pair and returns the `value` for use. +Like `.get()`, `.pop()` accepts second argument (_`dict.pop(, )`_) that will be returned if the `key` is not found. +This prevents a `KeyError` being raised: + +```python +#Using .pop() removes both the key and value, returning the value. +>>> bear.pop("name") +'Grizzly Bear' + + +#The "name" key is now removed from the dictionary. +#Attempting .pop() a second time will throw a KeyError. +>>> bear.pop("name") +Traceback (most recent call last): + File "", line 1, in +KeyError: 'name' + + +#Using a default argument with .pop() will prevent a KeyError from a missing key. +>>> bear.pop("name", "Unknown") +'Unknown' +``` + +## Looping through/Iterating over a Dictionary + +Looping through a dictionary using `for item in dict` or `while item` will iterate over only the _keys_ by default. +You can access the _values_ within the same loop by using _square brackets_: + +```python +>>> for key in bear: +>>> print((key, bear[key])) #this forms a tuple of (key, value) and prints it. +('name', 'Black Bear') +('speed', 40) +('land_animal', True) +``` + +You can also use the `.items()` method, which returns (`key`, `value`) tuples automatically: + +```python +#dict.items() forms (key, value tuples) that can be unpacked and iterated over. +>>> for key, value in whale.items(): +>>> print(key, ":", value) +name : Blue Whale +speed : 25 +land_animal : False +blowholes : 1 +``` + +Likewise, the `.keys()` method will return `keys` and the `.values()` method will return the `values`. + +[associative-array]: https://en.wikipedia.org/wiki/Associative_array#:~:text=In%20computer%20science%2C%20an%20associative,a%20function%20with%20finite%20domain. +[hashtable-wikipedia]: https://en.wikipedia.org/wiki/Hash_table +[mapping-types-dict]: https://docs.python.org/3/library/stdtypes.html#mapping-types-dict +[term-hashable]: https://docs.python.org/3/glossary.html#term-hashable + +## Instructions + +In this exercise, you will be managing an inventory system. + +The inventory should be organized by the item name and it should keep track of the number of items available. + +You will have to handle adding items to an inventory. +Each time an item appears in a given list, the item's quantity should be increased by `1` in the inventory. +You will also have to handle deleting items from an inventory by decreasing quantities by `1` when requested. + +Finally, you will need to implement a function that will return all the key-value pairs in a given inventory as a `list` of `tuples`. + + +## 1. Create an inventory based on a list + +Implement the `create_inventory()` function that creates an "inventory" from an input list of items. +It should return a `dict` containing each item name paired with their respective quantity. + +```python +>>> create_inventory(["coal", "wood", "wood", "diamond", "diamond", "diamond"]) +{"coal":1, "wood":2, "diamond":3} +``` + +## 2. Add items from a list to an existing dictionary + +Implement the `add_items(, )` function that adds a list of items to the passed-in inventory: + +```python +>>> add_items({"coal":1}, ["wood", "iron", "coal", "wood"]) +{"coal":2, "wood":2, "iron":1} +``` + +## 3. Decrement items from the inventory + +Implement the `decrement_items(, )` function that takes a `list` of items. +Your function should remove `1` from an item count for each time that item appears on the `list`: + +```python +>>> decrement_items({"coal":3, "diamond":1, "iron":5}, ["diamond", "coal", "iron", "iron"]) +{"coal":2, "diamond":0, "iron":3} +``` + +Item counts in the inventory should not be allowed to fall below 0. + If the number of times an item appears on the input `list` exceeds the count available, the quantity listed for that item should remain at 0. + Additional requests for removing counts should be ignored once the count falls to zero. + +```python +>>> decrement_items({"coal":2, "wood":1, "diamond":2}, ["coal", "coal", "wood", "wood", "diamond"]) +{"coal":0, "wood":0, "diamond":1} +``` + +## 4. Remove an entry entirely from the inventory + +Implement the `remove_item(, )` function that removes an item and its count entirely from an inventory: + +```python +>>> remove_item({"coal":2, "wood":1, "diamond":2}, "coal") +{"wood":1, "diamond":2} +``` + +If the item is not found in the inventory, the function should return the original inventory unchanged. + +```python +>>> remove_item({"coal":2, "wood":1, "diamond":2}, "gold") +{"coal":2, "wood":1, "diamond":2} +``` + +## 5. Return the entire content of the inventory + +Implement the `list_inventory()` function that takes an inventory and returns a list of `(item, quantity)` tuples. +The list should only include the _available_ items (_with a quantity greater than zero_): + +```python +>>> list_inventory({"coal":7, "wood":11, "diamond":2, "iron":7, "silver":0}) +[('coal', 7), ('diamond', 2), ('iron', 7), ('wood', 11)] +``` + +## Source + +### Created by + +- @j08k + +### Contributed to by + +- @valentin-p +- @bethanyG +- @mukeshgurpude +- @kotp \ No newline at end of file diff --git a/python/inventory-management/__pycache__/dicts.cpython-313.pyc b/python/inventory-management/__pycache__/dicts.cpython-313.pyc new file mode 100644 index 0000000..65b125f Binary files /dev/null and b/python/inventory-management/__pycache__/dicts.cpython-313.pyc differ diff --git a/python/inventory-management/__pycache__/dicts.cpython-314.pyc b/python/inventory-management/__pycache__/dicts.cpython-314.pyc new file mode 100644 index 0000000..08f501d Binary files /dev/null and b/python/inventory-management/__pycache__/dicts.cpython-314.pyc differ diff --git a/python/inventory-management/__pycache__/dicts_test.cpython-313-pytest-8.3.4.pyc b/python/inventory-management/__pycache__/dicts_test.cpython-313-pytest-8.3.4.pyc new file mode 100644 index 0000000..4705b90 Binary files /dev/null and b/python/inventory-management/__pycache__/dicts_test.cpython-313-pytest-8.3.4.pyc differ diff --git a/python/inventory-management/__pycache__/dicts_test.cpython-314-pytest-9.1.0.pyc b/python/inventory-management/__pycache__/dicts_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..271fa25 Binary files /dev/null and b/python/inventory-management/__pycache__/dicts_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/inventory-management/dicts.py b/python/inventory-management/dicts.py new file mode 100644 index 0000000..4a50747 --- /dev/null +++ b/python/inventory-management/dicts.py @@ -0,0 +1,80 @@ +"""Functions to keep track and alter inventory.""" + + +def create_inventory(items): + """Create a dict that tracks the amount (count) of each element on the `items` list. + + :param items: list - list of items to create an inventory from. + :return: dict - the inventory dictionary. + """ + inventory: dict = {} + for item in items: + inventory[item] = items.count(item) + return inventory + + +def add_items(inventory, items): + """Add or increment items in inventory using elements from the items `list`. + + :param inventory: dict - dictionary of existing inventory. + :param items: list - list of items to update the inventory with. + :return: dict - the inventory updated with the new items. + """ + # inventory is empty, create new one and return inventory + if inventory == {}: + return create_inventory(items) + # increment items that already exists in inventory + for item in inventory: + inventory[item] += items.count(item) + # add new items that doesnt exist in inventory + # the new items can only be added after incrementing items that already + # exists in inventory to avoid adding the new items again + for item in items: + if item not in inventory: + inventory[item] = items.count(item) + return inventory + + +def decrement_items(inventory, items): + """Decrement items in inventory using elements from the `items` list. + + :param inventory: dict - inventory dictionary. + :param items: list - list of items to decrement from the inventory. + :return: dict - updated inventory with items decremented. + """ + for item in inventory: + if item in items: + inventory[item] -= items.count(item) + if inventory[item] < 0: + inventory[item] = 0 + return inventory + + +def remove_item(inventory, item): + """Remove item from inventory if it matches `item` string. + + :param inventory: dict - inventory dictionary. + :param item: str - item to remove from the inventory. + :return: dict - updated inventory with item removed. Current inventory if item does not match. + """ + if item in inventory: + inventory.pop(item) + return inventory + + +def list_inventory(inventory): + """Create a list containing only available (item_name, item_count > 0) pairs in inventory. + + :param inventory: dict - an inventory dictionary. + :return: list of tuples - list of key, value pairs from the inventory dictionary. + """ + inventory_list: list[tuple] = [] + # conventional + # for item in inventory: + # if inventory[item] > 0: + # inventory_list.append((item, inventory[item])) + # using list comprehension + inventory_list = [ + (item, inventory[item]) for item in inventory if inventory[item] > 0 + ] + return inventory_list diff --git a/python/inventory-management/dicts_test.py b/python/inventory-management/dicts_test.py new file mode 100644 index 0000000..71a8ff2 --- /dev/null +++ b/python/inventory-management/dicts_test.py @@ -0,0 +1,120 @@ +import unittest +import pytest +from dicts import (create_inventory, + add_items, + decrement_items, + remove_item, + list_inventory) + + +class InventoryTest(unittest.TestCase): + + @pytest.mark.task(taskno=1) + def test_create_inventory(self): + + actual_result = create_inventory(["wood", "iron", "iron", "diamond", "diamond"]) + expected = {"wood": 1, "iron": 2, "diamond": 2} + error_message = ('Called create_inventory(["wood", "iron", "iron", "diamond", "diamond"]). ' + f'The function returned {actual_result}, but the tests expected {expected}.') + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=2) + def test_add_one_item(self): + actual_result = add_items({"wood": 4, "iron": 2}, ["iron", "iron"]) + expected = {"wood": 4, "iron": 4} + error_message = ('Called add_items({"wood": 4, "iron": 2}, ["iron", "iron"]). ' + f'The function returned {actual_result}, but the tests expected {expected}.') + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=2) + def test_add_multiple_items(self): + actual_result = add_items({"wood": 2, "gold": 1, "diamond": 3}, ["wood", "gold", "gold"]) + expected = {"wood": 3, "gold": 3, "diamond": 3} + error_message = ('Called add_items({"wood": 2, "gold": 1, "diamond": 3}, ["wood", "gold", "gold"]). ' + f'The function returned {actual_result}, but the tests expected {expected}.') + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=2) + def test_add_new_item(self): + actual_result = add_items({"iron": 1, "diamond": 2}, ["iron", "wood", "wood"]) + expected = {"iron": 2, "diamond": 2, "wood": 2} + error_message = ('Called add_items({"iron": 1, "diamond": 2}, ["iron", "wood", "wood"]). ' + f'The function returned {actual_result}, but the tests expected {expected}.') + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=2) + def test_add_from_empty_dict(self): + actual_result = add_items({}, ["iron", "iron", "diamond"]) + expected = {"iron": 2, "diamond": 1} + error_message = ('Called add_items({}, ["iron", "iron", "diamond"]). ' + f'The function returned {actual_result}, but the tests expected {expected}.') + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=3) + def test_decrement_items(self): + actual_result = decrement_items({"iron": 3, "diamond": 4, "gold": 2}, + ["iron", "iron", "diamond", "gold", "gold"]) + expected = {"iron": 1, "diamond": 3, "gold": 0} + error_message = ('Called decrement_items({"iron": 3, "diamond": 4, "gold": 2},' + '["iron", "iron", "diamond", "gold", "gold"]). The function ' + f'returned {actual_result}, but the tests expected {expected}.') + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=3) + def test_not_below_zero(self): + actual_result = decrement_items({"wood": 2, "iron": 3, "diamond": 1}, + ["wood", "wood", "wood", "iron", "diamond", "diamond"]) + expected = {"wood": 0, "iron": 2, "diamond": 0} + error_message = ('Called decrement_items({"wood": 2, "iron": 3, "diamond": 1}, ' + '["wood", "wood", "wood", "iron", "diamond", "diamond"]). The ' + f'function returned {actual_result}, but the tests expected {expected}.') + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=3) + def test_decrement_items_not_in_inventory(self): + actual_result = decrement_items({"iron": 3, "gold": 2}, + ["iron", "wood", "iron", "diamond"]) + + expected = {"iron": 1, "gold": 2} + error_message = ('Called decrement_items({"iron": 3, "gold": 2}, ' + '["iron", "wood", "iron", "diamond"]). The function ' + f'returned {actual_result}, but the tests ' + f'expected {expected}.') + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=4) + def test_remove_item(self): + actual_result = remove_item({"iron": 1, "diamond": 2, "gold": 1}, "diamond") + expected = {"iron": 1, "gold": 1} + error_message = ('Called remove_item({"iron": 1, "diamond": 2, "gold": 1}, "diamond"). ' + f'The function returned {actual_result}, but the tests expected {expected}.') + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=4) + def test_remove_item_not_in_inventory(self): + actual_result = remove_item({"iron": 1, "diamond": 2, "gold": 1}, "wood") + expected = {"iron": 1, "gold": 1, "diamond": 2} + error_message = ('Called remove_item({"iron": 1, "diamond": 2, "gold": 1}, "wood"). ' + f'The function returned {actual_result}, ' + f'but the tests expected {expected}.') + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=5) + def test_list_inventory(self): + actual_result = list_inventory({"coal": 15, "diamond": 3, "wood": 67, "silver": 0}) + expected = [("coal", 15), ("diamond", 3), ("wood", 67)] + error_message = ('Called list_inventory({"coal": 15, "diamond": 3, "wood": 67, "silver": 0}). ' + f'The function returned {actual_result}, ' + f'but the tests expected {expected}.') + + self.assertEqual(actual_result, expected, msg=error_message) diff --git a/python/isbn-verifier/.exercism/config.json b/python/isbn-verifier/.exercism/config.json new file mode 100644 index 0000000..78b6dcc --- /dev/null +++ b/python/isbn-verifier/.exercism/config.json @@ -0,0 +1,27 @@ +{ + "authors": [ + "pheanex" + ], + "contributors": [ + "BethanyG", + "cmccandless", + "Dog", + "thomasjpfan", + "tqa236", + "yawpitch" + ], + "files": { + "solution": [ + "isbn_verifier.py" + ], + "test": [ + "isbn_verifier_test.py" + ], + "example": [ + ".meta/example.py" + ] + }, + "blurb": "Check if a given string is a valid ISBN-10 number.", + "source": "Converting a string into a number and some basic processing utilizing a relatable real world example.", + "source_url": "https://en.wikipedia.org/wiki/International_Standard_Book_Number#ISBN-10_check_digit_calculation" +} diff --git a/python/isbn-verifier/.exercism/metadata.json b/python/isbn-verifier/.exercism/metadata.json new file mode 100644 index 0000000..31f33c3 --- /dev/null +++ b/python/isbn-verifier/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"isbn-verifier","id":"ea0dcdf76bbb4c899e829912e28f0179","url":"https://exercism.org/tracks/python/exercises/isbn-verifier","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/isbn-verifier/HELP.md b/python/isbn-verifier/HELP.md new file mode 100644 index 0000000..d3cc7be --- /dev/null +++ b/python/isbn-verifier/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +
+ +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit isbn_verifier.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/isbn-verifier/README.md b/python/isbn-verifier/README.md new file mode 100644 index 0000000..ef6a5c8 --- /dev/null +++ b/python/isbn-verifier/README.md @@ -0,0 +1,66 @@ +# ISBN Verifier + +Welcome to ISBN Verifier on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Instructions + +The [ISBN-10 verification process][isbn-verification] is used to validate book identification numbers. +These normally contain dashes and look like: `3-598-21508-8` + +## ISBN + +The ISBN-10 format is 9 digits (0 to 9) plus one check character (either a digit or an X only). +In the case the check character is an X, this represents the value '10'. +These may be communicated with or without hyphens, and can be checked for their validity by the following formula: + +```text +(d₁ * 10 + d₂ * 9 + d₃ * 8 + d₄ * 7 + d₅ * 6 + d₆ * 5 + d₇ * 4 + d₈ * 3 + d₉ * 2 + d₁₀ * 1) mod 11 == 0 +``` + +If the result is 0, then it is a valid ISBN-10, otherwise it is invalid. + +## Example + +Let's take the ISBN-10 `3-598-21508-8`. +We plug it in to the formula, and get: + +```text +(3 * 10 + 5 * 9 + 9 * 8 + 8 * 7 + 2 * 6 + 1 * 5 + 5 * 4 + 0 * 3 + 8 * 2 + 8 * 1) mod 11 == 0 +``` + +Since the result is 0, this proves that our ISBN is valid. + +## Task + +Given a string the program should check if the provided string is a valid ISBN-10. +Putting this into place requires some thinking about preprocessing/parsing of the string prior to calculating the check digit for the ISBN. + +The program should be able to verify ISBN-10 both with and without separating dashes. + +## Caveats + +Converting from strings to numbers can be tricky in certain languages. +Now, it's even trickier since the check digit of an ISBN-10 may be 'X' (representing '10'). +For instance `3-598-21507-X` is a valid ISBN-10. + +[isbn-verification]: https://en.wikipedia.org/wiki/International_Standard_Book_Number + +## Source + +### Created by + +- @pheanex + +### Contributed to by + +- @BethanyG +- @cmccandless +- @Dog +- @thomasjpfan +- @tqa236 +- @yawpitch + +### Based on + +Converting a string into a number and some basic processing utilizing a relatable real world example. - https://en.wikipedia.org/wiki/International_Standard_Book_Number#ISBN-10_check_digit_calculation \ No newline at end of file diff --git a/python/isbn-verifier/__pycache__/isbn_verifier.cpython-313.pyc b/python/isbn-verifier/__pycache__/isbn_verifier.cpython-313.pyc new file mode 100644 index 0000000..6b9e20c Binary files /dev/null and b/python/isbn-verifier/__pycache__/isbn_verifier.cpython-313.pyc differ diff --git a/python/isbn-verifier/__pycache__/isbn_verifier.cpython-314.pyc b/python/isbn-verifier/__pycache__/isbn_verifier.cpython-314.pyc new file mode 100644 index 0000000..e006f9c Binary files /dev/null and b/python/isbn-verifier/__pycache__/isbn_verifier.cpython-314.pyc differ diff --git a/python/isbn-verifier/__pycache__/isbn_verifier_test.cpython-313-pytest-8.3.4.pyc b/python/isbn-verifier/__pycache__/isbn_verifier_test.cpython-313-pytest-8.3.4.pyc new file mode 100644 index 0000000..14603a3 Binary files /dev/null and b/python/isbn-verifier/__pycache__/isbn_verifier_test.cpython-313-pytest-8.3.4.pyc differ diff --git a/python/isbn-verifier/__pycache__/isbn_verifier_test.cpython-314-pytest-9.1.0.pyc b/python/isbn-verifier/__pycache__/isbn_verifier_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..f2c3c1f Binary files /dev/null and b/python/isbn-verifier/__pycache__/isbn_verifier_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/isbn-verifier/isbn_verifier.py b/python/isbn-verifier/isbn_verifier.py new file mode 100644 index 0000000..a185d85 --- /dev/null +++ b/python/isbn-verifier/isbn_verifier.py @@ -0,0 +1,24 @@ +def is_valid(isbn): + # remove dashes + isbn_no_dashes: str = "".join(isbn.split("-")) + sum: int = 0 + # is isbn empty + if isbn == "": + return False + # isbn length must be 10 + if len(isbn_no_dashes) < 10 or len(isbn_no_dashes) > 10: + return False + for index, digit in enumerate(isbn_no_dashes): + # non-digit in isbn not as a checksum, return False + if digit.isalpha() and index != 9: + return False + # if its a digit, ok + if digit.isdigit(): + sum += int(digit) * (10 - index) + # if check digit is not digit or not an 'X', return False + if index == 9 and digit.isalpha() and digit.lower() != "x": + return False + # if check digit is the letter 'X' treat it as a 10 + if digit.isalpha() and index == 9 and digit.lower() == "x": + sum += 10 * (10 - index) + return False if sum % 11 else True diff --git a/python/isbn-verifier/isbn_verifier_test.py b/python/isbn-verifier/isbn_verifier_test.py new file mode 100644 index 0000000..dbcddf1 --- /dev/null +++ b/python/isbn-verifier/isbn_verifier_test.py @@ -0,0 +1,68 @@ +# These tests are auto-generated with test data from: +# https://github.com/exercism/problem-specifications/tree/main/exercises/isbn-verifier/canonical-data.json +# File last updated on 2023-07-19 + +import unittest + +from isbn_verifier import ( + is_valid, +) + + +class IsbnVerifierTest(unittest.TestCase): + def test_valid_isbn(self): + self.assertIs(is_valid("3-598-21508-8"), True) + + def test_invalid_isbn_check_digit(self): + self.assertIs(is_valid("3-598-21508-9"), False) + + def test_valid_isbn_with_a_check_digit_of_10(self): + self.assertIs(is_valid("3-598-21507-X"), True) + + def test_check_digit_is_a_character_other_than_x(self): + self.assertIs(is_valid("3-598-21507-A"), False) + + def test_invalid_check_digit_in_isbn_is_not_treated_as_zero(self): + self.assertIs(is_valid("4-598-21507-B"), False) + + def test_invalid_character_in_isbn_is_not_treated_as_zero(self): + self.assertIs(is_valid("3-598-P1581-X"), False) + + def test_x_is_only_valid_as_a_check_digit(self): + self.assertIs(is_valid("3-598-2X507-9"), False) + + def test_valid_isbn_without_separating_dashes(self): + self.assertIs(is_valid("3598215088"), True) + + def test_isbn_without_separating_dashes_and_x_as_check_digit(self): + self.assertIs(is_valid("359821507X"), True) + + def test_isbn_without_check_digit_and_dashes(self): + self.assertIs(is_valid("359821507"), False) + + def test_too_long_isbn_and_no_dashes(self): + self.assertIs(is_valid("3598215078X"), False) + + def test_too_short_isbn(self): + self.assertIs(is_valid("00"), False) + + def test_isbn_without_check_digit(self): + self.assertIs(is_valid("3-598-21507"), False) + + def test_check_digit_of_x_should_not_be_used_for_0(self): + self.assertIs(is_valid("3-598-21515-X"), False) + + def test_empty_isbn(self): + self.assertIs(is_valid(""), False) + + def test_input_is_9_characters(self): + self.assertIs(is_valid("134456729"), False) + + def test_invalid_characters_are_not_ignored_after_checking_length(self): + self.assertIs(is_valid("3132P34035"), False) + + def test_invalid_characters_are_not_ignored_before_checking_length(self): + self.assertIs(is_valid("3598P215088"), False) + + def test_input_is_too_long_but_contains_a_valid_isbn(self): + self.assertIs(is_valid("98245726788"), False) diff --git a/python/isogram/.exercism/config.json b/python/isogram/.exercism/config.json new file mode 100644 index 0000000..302b30a --- /dev/null +++ b/python/isogram/.exercism/config.json @@ -0,0 +1,33 @@ +{ + "authors": [ + "behrtam" + ], + "contributors": [ + "abhijitparida", + "cmccandless", + "Dog", + "ikhadykin", + "N-Parsons", + "Nishant23", + "olufotebig", + "rever0f", + "sdublish", + "thomasjpfan", + "tqa236", + "yawpitch" + ], + "files": { + "solution": [ + "isogram.py" + ], + "test": [ + "isogram_test.py" + ], + "example": [ + ".meta/example.py" + ] + }, + "blurb": "Determine if a word or phrase is an isogram.", + "source": "Wikipedia", + "source_url": "https://en.wikipedia.org/wiki/Isogram" +} diff --git a/python/isogram/.exercism/metadata.json b/python/isogram/.exercism/metadata.json new file mode 100644 index 0000000..327caf5 --- /dev/null +++ b/python/isogram/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"isogram","id":"3a9e509e36ca4687aa85554b294144da","url":"https://exercism.org/tracks/python/exercises/isogram","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/isogram/HELP.md b/python/isogram/HELP.md new file mode 100644 index 0000000..f0ebb96 --- /dev/null +++ b/python/isogram/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +
+ +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit isogram.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/isogram/README.md b/python/isogram/README.md new file mode 100644 index 0000000..1472a36 --- /dev/null +++ b/python/isogram/README.md @@ -0,0 +1,44 @@ +# Isogram + +Welcome to Isogram on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Instructions + +Determine if a word or phrase is an isogram. + +An isogram (also known as a "non-pattern word") is a word or phrase without a repeating letter, however spaces and hyphens are allowed to appear multiple times. + +Examples of isograms: + +- lumberjacks +- background +- downstream +- six-year-old + +The word _isograms_, however, is not an isogram, because the s repeats. + +## Source + +### Created by + +- @behrtam + +### Contributed to by + +- @abhijitparida +- @cmccandless +- @Dog +- @ikhadykin +- @N-Parsons +- @Nishant23 +- @olufotebig +- @rever0f +- @sdublish +- @thomasjpfan +- @tqa236 +- @yawpitch + +### Based on + +Wikipedia - https://en.wikipedia.org/wiki/Isogram \ No newline at end of file diff --git a/python/isogram/__pycache__/isogram.cpython-313.pyc b/python/isogram/__pycache__/isogram.cpython-313.pyc new file mode 100644 index 0000000..c5638b3 Binary files /dev/null and b/python/isogram/__pycache__/isogram.cpython-313.pyc differ diff --git a/python/isogram/__pycache__/isogram.cpython-314.pyc b/python/isogram/__pycache__/isogram.cpython-314.pyc new file mode 100644 index 0000000..30f5939 Binary files /dev/null and b/python/isogram/__pycache__/isogram.cpython-314.pyc differ diff --git a/python/isogram/__pycache__/isogram_test.cpython-313-pytest-8.3.4.pyc b/python/isogram/__pycache__/isogram_test.cpython-313-pytest-8.3.4.pyc new file mode 100644 index 0000000..692138c Binary files /dev/null and b/python/isogram/__pycache__/isogram_test.cpython-313-pytest-8.3.4.pyc differ diff --git a/python/isogram/__pycache__/isogram_test.cpython-314-pytest-9.1.0.pyc b/python/isogram/__pycache__/isogram_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..1e68873 Binary files /dev/null and b/python/isogram/__pycache__/isogram_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/isogram/isogram.py b/python/isogram/isogram.py new file mode 100644 index 0000000..79b0fa2 --- /dev/null +++ b/python/isogram/isogram.py @@ -0,0 +1,6 @@ +def is_isogram(string): + # use string method count() when letter.isalpha() == True + for letter in string.lower(): + if letter.isalpha() and string.lower().count(letter) > 1: + return False + return True diff --git a/python/isogram/isogram_test.py b/python/isogram/isogram_test.py new file mode 100644 index 0000000..c65984f --- /dev/null +++ b/python/isogram/isogram_test.py @@ -0,0 +1,53 @@ +# These tests are auto-generated with test data from: +# https://github.com/exercism/problem-specifications/tree/main/exercises/isogram/canonical-data.json +# File last updated on 2023-07-19 + +import unittest + +from isogram import ( + is_isogram, +) + + +class IsogramTest(unittest.TestCase): + def test_empty_string(self): + self.assertIs(is_isogram(""), True) + + def test_isogram_with_only_lower_case_characters(self): + self.assertIs(is_isogram("isogram"), True) + + def test_word_with_one_duplicated_character(self): + self.assertIs(is_isogram("eleven"), False) + + def test_word_with_one_duplicated_character_from_the_end_of_the_alphabet(self): + self.assertIs(is_isogram("zzyzx"), False) + + def test_longest_reported_english_isogram(self): + self.assertIs(is_isogram("subdermatoglyphic"), True) + + def test_word_with_duplicated_character_in_mixed_case(self): + self.assertIs(is_isogram("Alphabet"), False) + + def test_word_with_duplicated_character_in_mixed_case_lowercase_first(self): + self.assertIs(is_isogram("alphAbet"), False) + + def test_hypothetical_isogrammic_word_with_hyphen(self): + self.assertIs(is_isogram("thumbscrew-japingly"), True) + + def test_hypothetical_word_with_duplicated_character_following_hyphen(self): + self.assertIs(is_isogram("thumbscrew-jappingly"), False) + + def test_isogram_with_duplicated_hyphen(self): + self.assertIs(is_isogram("six-year-old"), True) + + def test_made_up_name_that_is_an_isogram(self): + self.assertIs(is_isogram("Emily Jung Schwartzkopf"), True) + + def test_duplicated_character_in_the_middle(self): + self.assertIs(is_isogram("accentor"), False) + + def test_same_first_and_last_characters(self): + self.assertIs(is_isogram("angola"), False) + + def test_word_with_duplicated_character_and_with_two_hyphens(self): + self.assertIs(is_isogram("up-to-date"), False) diff --git a/python/leap/.exercism/config.json b/python/leap/.exercism/config.json new file mode 100644 index 0000000..1c35f22 --- /dev/null +++ b/python/leap/.exercism/config.json @@ -0,0 +1,38 @@ +{ + "authors": [], + "contributors": [ + "AnAccountForReportingBugs", + "behrtam", + "BethanyG", + "betojulio", + "cmccandless", + "cruxicheiros", + "Dog", + "fluxusfrequency", + "iandexter", + "ikhadykin", + "kytrinyx", + "lowks", + "N-Parsons", + "olufotebig", + "pheanex", + "sambryant4", + "sjakobi", + "tqa236", + "yawpitch" + ], + "files": { + "solution": [ + "leap.py" + ], + "test": [ + "leap_test.py" + ], + "example": [ + ".meta/example.py" + ] + }, + "blurb": "Determine whether a given year is a leap year.", + "source": "CodeRanch Cattle Drive, Assignment 3", + "source_url": "https://coderanch.com/t/718816/Leap" +} diff --git a/python/leap/.exercism/metadata.json b/python/leap/.exercism/metadata.json new file mode 100644 index 0000000..3d8a581 --- /dev/null +++ b/python/leap/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"leap","id":"c87e972483d5467ab5b7cb1b52c9203c","url":"https://exercism.org/tracks/python/exercises/leap","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/leap/HELP.md b/python/leap/HELP.md new file mode 100644 index 0000000..13ed4ec --- /dev/null +++ b/python/leap/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +
+ +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit leap.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/leap/README.md b/python/leap/README.md new file mode 100644 index 0000000..e41fdaf --- /dev/null +++ b/python/leap/README.md @@ -0,0 +1,53 @@ +# Leap + +Welcome to Leap on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Introduction + +A leap year (in the Gregorian calendar) occurs: + +- In every year that is evenly divisible by 4. +- Unless the year is evenly divisible by 100, in which case it's only a leap year if the year is also evenly divisible by 400. + +Some examples: + +- 1997 was not a leap year as it's not divisible by 4. +- 1900 was not a leap year as it's not divisible by 400. +- 2000 was a leap year! + +~~~~exercism/note +For a delightful, four-minute explanation of the whole phenomenon of leap years, check out [this YouTube video](https://www.youtube.com/watch?v=xX96xng7sAE). +~~~~ + +## Instructions + +Your task is to determine whether a given year is a leap year. + +## Source + +### Contributed to by + +- @AnAccountForReportingBugs +- @behrtam +- @BethanyG +- @betojulio +- @cmccandless +- @cruxicheiros +- @Dog +- @fluxusfrequency +- @iandexter +- @ikhadykin +- @kytrinyx +- @lowks +- @N-Parsons +- @olufotebig +- @pheanex +- @sambryant4 +- @sjakobi +- @tqa236 +- @yawpitch + +### Based on + +CodeRanch Cattle Drive, Assignment 3 - https://coderanch.com/t/718816/Leap \ No newline at end of file diff --git a/python/leap/__pycache__/leap.cpython-313.pyc b/python/leap/__pycache__/leap.cpython-313.pyc new file mode 100644 index 0000000..77979d5 Binary files /dev/null and b/python/leap/__pycache__/leap.cpython-313.pyc differ diff --git a/python/leap/__pycache__/leap.cpython-314.pyc b/python/leap/__pycache__/leap.cpython-314.pyc new file mode 100644 index 0000000..d9ccb01 Binary files /dev/null and b/python/leap/__pycache__/leap.cpython-314.pyc differ diff --git a/python/leap/__pycache__/leap_test.cpython-313-pytest-8.3.4.pyc b/python/leap/__pycache__/leap_test.cpython-313-pytest-8.3.4.pyc new file mode 100644 index 0000000..79cd926 Binary files /dev/null and b/python/leap/__pycache__/leap_test.cpython-313-pytest-8.3.4.pyc differ diff --git a/python/leap/__pycache__/leap_test.cpython-314-pytest-9.1.0.pyc b/python/leap/__pycache__/leap_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..ffb2a63 Binary files /dev/null and b/python/leap/__pycache__/leap_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/leap/leap.py b/python/leap/leap.py new file mode 100644 index 0000000..b6594cf --- /dev/null +++ b/python/leap/leap.py @@ -0,0 +1,2 @@ +def leap_year(year): + return (year % 4 == 0) and (year % 100 != 0 or year % 400 == 0) diff --git a/python/leap/leap_test.py b/python/leap/leap_test.py new file mode 100644 index 0000000..6a1d732 --- /dev/null +++ b/python/leap/leap_test.py @@ -0,0 +1,38 @@ +# These tests are auto-generated with test data from: +# https://github.com/exercism/problem-specifications/tree/main/exercises/leap/canonical-data.json +# File last updated on 2023-07-19 + +import unittest + +from leap import ( + leap_year, +) + + +class LeapTest(unittest.TestCase): + def test_year_not_divisible_by_4_in_common_year(self): + self.assertIs(leap_year(2015), False) + + def test_year_divisible_by_2_not_divisible_by_4_in_common_year(self): + self.assertIs(leap_year(1970), False) + + def test_year_divisible_by_4_not_divisible_by_100_in_leap_year(self): + self.assertIs(leap_year(1996), True) + + def test_year_divisible_by_4_and_5_is_still_a_leap_year(self): + self.assertIs(leap_year(1960), True) + + def test_year_divisible_by_100_not_divisible_by_400_in_common_year(self): + self.assertIs(leap_year(2100), False) + + def test_year_divisible_by_100_but_not_by_3_is_still_not_a_leap_year(self): + self.assertIs(leap_year(1900), False) + + def test_year_divisible_by_400_is_leap_year(self): + self.assertIs(leap_year(2000), True) + + def test_year_divisible_by_400_but_not_by_125_is_still_a_leap_year(self): + self.assertIs(leap_year(2400), True) + + def test_year_divisible_by_200_not_divisible_by_400_in_common_year(self): + self.assertIs(leap_year(1800), False) diff --git a/python/line-up/.exercism/config.json b/python/line-up/.exercism/config.json new file mode 100644 index 0000000..c741712 --- /dev/null +++ b/python/line-up/.exercism/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "BNAndras" + ], + "files": { + "solution": [ + "line_up.py" + ], + "test": [ + "line_up_test.py" + ], + "example": [ + ".meta/example.py" + ] + }, + "blurb": "Help lining up customers at Yaʻqūb's Deli.", + "source": "mk-mxp, based on previous work from Exercism contributors codedge and neenjaw", + "source_url": "https://forum.exercism.org/t/new-exercise-ordinal-numbers/19147" +} diff --git a/python/line-up/.exercism/metadata.json b/python/line-up/.exercism/metadata.json new file mode 100644 index 0000000..82086d9 --- /dev/null +++ b/python/line-up/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"line-up","id":"d0c2453a1ae5498a9727a6c50298a90a","url":"https://exercism.org/tracks/python/exercises/line-up","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/line-up/HELP.md b/python/line-up/HELP.md new file mode 100644 index 0000000..e032658 --- /dev/null +++ b/python/line-up/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd +``` + +Windows +```powershell +PS C:\Users\foobar> cd +``` + +
+ +Next, run the `pytest` command in your terminal, replacing `` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit line_up.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [Python Community Forums](https://discuss.python.org/) help, PEP discussion, core Python committers, and more. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [The Exercism Community Discussion Forums](https://forum.exercsim.org) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/line-up/README.md b/python/line-up/README.md new file mode 100644 index 0000000..5144459 --- /dev/null +++ b/python/line-up/README.md @@ -0,0 +1,42 @@ +# Line Up + +Welcome to Line Up on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Introduction + +Your friend Yaʻqūb works the counter at a deli in town, slicing, weighing, and wrapping orders for a line of hungry customers that gets longer every day. +Waiting customers are starting to lose track of who is next, so he wants numbered tickets they can use to track the order in which they arrive. + +To make the customers feel special, he does not want the ticket to have only a number on it. +They shall get a proper English sentence with their name and number on it. + +## Instructions + +Given a name and a number, your task is to produce a sentence using that name and that number as an [ordinal numeral][ordinal-numeral]. +Yaʻqūb expects to use numbers from 1 up to 999. + +Rules: + +- Numbers ending in 1 (unless ending in 11) → `"st"` +- Numbers ending in 2 (unless ending in 12) → `"nd"` +- Numbers ending in 3 (unless ending in 13) → `"rd"` +- All other numbers → `"th"` + +Examples: + +- `"Mary", 1` → `"Mary, you are the 1st customer we serve today. Thank you!"` +- `"John", 12` → `"John, you are the 12th customer we serve today. Thank you!"` +- `"Dahir", 162` → `"Dahir, you are the 162nd customer we serve today. Thank you!"` + +[ordinal-numeral]: https://en.wikipedia.org/wiki/Ordinal_numeral + +## Source + +### Created by + +- @BNAndras + +### Based on + +mk-mxp, based on previous work from Exercism contributors codedge and neenjaw - https://forum.exercism.org/t/new-exercise-ordinal-numbers/19147 \ No newline at end of file diff --git a/python/line-up/__pycache__/line_up.cpython-314.pyc b/python/line-up/__pycache__/line_up.cpython-314.pyc new file mode 100644 index 0000000..f63c7c5 Binary files /dev/null and b/python/line-up/__pycache__/line_up.cpython-314.pyc differ diff --git a/python/line-up/__pycache__/line_up_test.cpython-314-pytest-9.1.0.pyc b/python/line-up/__pycache__/line_up_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..119f4e5 Binary files /dev/null and b/python/line-up/__pycache__/line_up_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/line-up/line_up.py b/python/line-up/line_up.py new file mode 100644 index 0000000..1c95d35 --- /dev/null +++ b/python/line-up/line_up.py @@ -0,0 +1,16 @@ +def line_up(name, number): + ordinal_sufix: str = "" + # for the special case when the tenths of the number is between 10 and 20 + # the ordinal of all numbers are equal to 'th' + if number % 100 > 10 and number % 100 < 20: + return f"{name}, you are the {number}th customer we serve today. Thank you!" + match number % 10: + case 1: + ordinal_sufix = "st" + case 2: + ordinal_sufix = "nd" + case 3: + ordinal_sufix = "rd" + case _: + ordinal_sufix = "th" + return f"{name}, you are the {number}{ordinal_sufix} customer we serve today. Thank you!" diff --git a/python/line-up/line_up_test.py b/python/line-up/line_up_test.py new file mode 100644 index 0000000..e77e553 --- /dev/null +++ b/python/line-up/line_up_test.py @@ -0,0 +1,173 @@ +# These tests are auto-generated with test data from: +# https://github.com/exercism/problem-specifications/tree/main/exercises/line-up/canonical-data.json +# File last updated on 2026-09-30 + +import unittest + +from line_up import ( + line_up, +) + + +class LineUpTest(unittest.TestCase): + def test_format_smallest_non_exceptional_ordinal_numeral_4(self): + self.assertEqual( + line_up("Gianna", 4), + "Gianna, you are the 4th customer we serve today. Thank you!", + ) + + def test_format_greatest_single_digit_non_exceptional_ordinal_numeral_9(self): + self.assertEqual( + line_up("Maarten", 9), + "Maarten, you are the 9th customer we serve today. Thank you!", + ) + + def test_format_non_exceptional_ordinal_numeral_5(self): + self.assertEqual( + line_up("Petronila", 5), + "Petronila, you are the 5th customer we serve today. Thank you!", + ) + + def test_format_non_exceptional_ordinal_numeral_6(self): + self.assertEqual( + line_up("Attakullakulla", 6), + "Attakullakulla, you are the 6th customer we serve today. Thank you!", + ) + + def test_format_non_exceptional_ordinal_numeral_7(self): + self.assertEqual( + line_up("Kate", 7), + "Kate, you are the 7th customer we serve today. Thank you!", + ) + + def test_format_non_exceptional_ordinal_numeral_8(self): + self.assertEqual( + line_up("Maximiliano", 8), + "Maximiliano, you are the 8th customer we serve today. Thank you!", + ) + + def test_format_exceptional_ordinal_numeral_1(self): + self.assertEqual( + line_up("Mary", 1), + "Mary, you are the 1st customer we serve today. Thank you!", + ) + + def test_format_exceptional_ordinal_numeral_2(self): + self.assertEqual( + line_up("Haruto", 2), + "Haruto, you are the 2nd customer we serve today. Thank you!", + ) + + def test_format_exceptional_ordinal_numeral_3(self): + self.assertEqual( + line_up("Henriette", 3), + "Henriette, you are the 3rd customer we serve today. Thank you!", + ) + + def test_format_smallest_two_digit_non_exceptional_ordinal_numeral_10(self): + self.assertEqual( + line_up("Alvarez", 10), + "Alvarez, you are the 10th customer we serve today. Thank you!", + ) + + def test_format_non_exceptional_ordinal_numeral_11(self): + self.assertEqual( + line_up("Jacqueline", 11), + "Jacqueline, you are the 11th customer we serve today. Thank you!", + ) + + def test_format_non_exceptional_ordinal_numeral_12(self): + self.assertEqual( + line_up("Juan", 12), + "Juan, you are the 12th customer we serve today. Thank you!", + ) + + def test_format_non_exceptional_ordinal_numeral_13(self): + self.assertEqual( + line_up("Patricia", 13), + "Patricia, you are the 13th customer we serve today. Thank you!", + ) + + def test_format_exceptional_ordinal_numeral_21(self): + self.assertEqual( + line_up("Washi", 21), + "Washi, you are the 21st customer we serve today. Thank you!", + ) + + def test_format_exceptional_ordinal_numeral_22_ending_in_nd_even_though_it_is_a_multiple_of_11( + self, + ): + self.assertEqual( + line_up("Ingrid", 22), + "Ingrid, you are the 22nd customer we serve today. Thank you!", + ) + + def test_format_exceptional_ordinal_numeral_33_ending_in_rd_even_though_it_is_a_multiple_of_11( + self, + ): + self.assertEqual( + line_up("Mario", 33), + "Mario, you are the 33rd customer we serve today. Thank you!", + ) + + def test_format_exceptional_ordinal_numeral_52_ending_in_nd_even_though_it_is_a_multiple_of_13( + self, + ): + self.assertEqual( + line_up("Quentin", 52), + "Quentin, you are the 52nd customer we serve today. Thank you!", + ) + + def test_format_exceptional_ordinal_numeral_62(self): + self.assertEqual( + line_up("Nayra", 62), + "Nayra, you are the 62nd customer we serve today. Thank you!", + ) + + def test_format_non_exceptional_ordinal_numeral_72_ending_in_nd_even_though_it_is_a_multiple_of_12( + self, + ): + self.assertEqual( + line_up("Ugo", 72), + "Ugo, you are the 72nd customer we serve today. Thank you!", + ) + + def test_format_exceptional_ordinal_numeral_91_ending_in_st_even_though_it_is_a_multiple_of_13( + self, + ): + self.assertEqual( + line_up("Boris", 91), + "Boris, you are the 91st customer we serve today. Thank you!", + ) + + def test_format_exceptional_ordinal_numeral_100(self): + self.assertEqual( + line_up("John", 100), + "John, you are the 100th customer we serve today. Thank you!", + ) + + def test_format_exceptional_ordinal_numeral_101(self): + self.assertEqual( + line_up("Zeinab", 101), + "Zeinab, you are the 101st customer we serve today. Thank you!", + ) + + def test_format_non_exceptional_ordinal_numeral_112(self): + self.assertEqual( + line_up("Knud", 112), + "Knud, you are the 112th customer we serve today. Thank you!", + ) + + def test_format_exceptional_ordinal_numeral_123(self): + self.assertEqual( + line_up("Yma", 123), + "Yma, you are the 123rd customer we serve today. Thank you!", + ) + + def test_format_large_number_972_ending_in_nd_even_though_it_is_a_multiple_of_12( + self, + ): + self.assertEqual( + line_up("Elias", 972), + "Elias, you are the 972nd customer we serve today. Thank you!", + ) diff --git a/python/list-ops/.exercism/config.json b/python/list-ops/.exercism/config.json new file mode 100644 index 0000000..cdb3313 --- /dev/null +++ b/python/list-ops/.exercism/config.json @@ -0,0 +1,30 @@ +{ + "authors": [ + "behrtam" + ], + "contributors": [ + "BethanyG", + "cmccandless", + "Dog", + "dvermd", + "gabriel376", + "IsaacG", + "N-Parsons", + "pheanex", + "rootulp", + "thomasjpfan", + "tqa236" + ], + "files": { + "solution": [ + "list_ops.py" + ], + "test": [ + "list_ops_test.py" + ], + "example": [ + ".meta/example.py" + ] + }, + "blurb": "Implement basic list operations." +} diff --git a/python/list-ops/.exercism/metadata.json b/python/list-ops/.exercism/metadata.json new file mode 100644 index 0000000..923a796 --- /dev/null +++ b/python/list-ops/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"list-ops","id":"55460b9e32674ede804dd7334d0322eb","url":"https://exercism.org/tracks/python/exercises/list-ops","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/list-ops/HELP.md b/python/list-ops/HELP.md new file mode 100644 index 0000000..9629152 --- /dev/null +++ b/python/list-ops/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +
+ +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit list_ops.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/list-ops/README.md b/python/list-ops/README.md new file mode 100644 index 0000000..1b1733b --- /dev/null +++ b/python/list-ops/README.md @@ -0,0 +1,44 @@ +# List Ops + +Welcome to List Ops on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Instructions + +Implement basic list operations. + +In functional languages list operations like `length`, `map`, and `reduce` are very common. +Implement a series of basic list operations, without using existing functions. + +The precise number and names of the operations to be implemented will be track dependent to avoid conflicts with existing names, but the general operations you will implement include: + +- `append` (_given two lists, add all items in the second list to the end of the first list_); +- `concatenate` (_given a series of lists, combine all items in all lists into one flattened list_); +- `filter` (_given a predicate and a list, return the list of all items for which `predicate(item)` is True_); +- `length` (_given a list, return the total number of items within it_); +- `map` (_given a function and a list, return the list of the results of applying `function(item)` on all items_); +- `foldl` (_given a function, a list, and initial accumulator, fold (reduce) each item into the accumulator from the left_); +- `foldr` (_given a function, a list, and an initial accumulator, fold (reduce) each item into the accumulator from the right_); +- `reverse` (_given a list, return a list with all the original items, but in reversed order_). + +Note, the ordering in which arguments are passed to the fold functions (`foldl`, `foldr`) is significant. + +## Source + +### Created by + +- @behrtam + +### Contributed to by + +- @BethanyG +- @cmccandless +- @Dog +- @dvermd +- @gabriel376 +- @IsaacG +- @N-Parsons +- @pheanex +- @rootulp +- @thomasjpfan +- @tqa236 \ No newline at end of file diff --git a/python/list-ops/__pycache__/list_ops.cpython-313.pyc b/python/list-ops/__pycache__/list_ops.cpython-313.pyc new file mode 100644 index 0000000..96a3dca Binary files /dev/null and b/python/list-ops/__pycache__/list_ops.cpython-313.pyc differ diff --git a/python/list-ops/__pycache__/list_ops.cpython-314.pyc b/python/list-ops/__pycache__/list_ops.cpython-314.pyc new file mode 100644 index 0000000..8454b15 Binary files /dev/null and b/python/list-ops/__pycache__/list_ops.cpython-314.pyc differ diff --git a/python/list-ops/__pycache__/list_ops_test.cpython-313-pytest-8.3.5.pyc b/python/list-ops/__pycache__/list_ops_test.cpython-313-pytest-8.3.5.pyc new file mode 100644 index 0000000..9051826 Binary files /dev/null and b/python/list-ops/__pycache__/list_ops_test.cpython-313-pytest-8.3.5.pyc differ diff --git a/python/list-ops/__pycache__/list_ops_test.cpython-314-pytest-9.1.0.pyc b/python/list-ops/__pycache__/list_ops_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..38d742a Binary files /dev/null and b/python/list-ops/__pycache__/list_ops_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/list-ops/list_ops.py b/python/list-ops/list_ops.py new file mode 100644 index 0000000..3b6639a --- /dev/null +++ b/python/list-ops/list_ops.py @@ -0,0 +1,73 @@ +from typing import Callable + + +# return the length of list +def length(list: list) -> int: + length: int = 0 + for _ in list: + length += 1 + return length + + +# append list2 at the end of list1 +def append(list1: list, list2: list) -> list: + new_list: list = [] + for index, item in enumerate(list1, 0): + new_list.insert(index, item) + for index, item in enumerate(list2, length(list1)): + new_list.insert(index, item) + return new_list + + +def concat(lists: list[list]): + new_list: list = [] + for item_list in lists: + new_list = append(new_list, item_list) + return new_list + + +def filter(function: Callable, list_of_items: list): + filtered_list: list = [] + insert_index: int = 0 + for item in list_of_items: + if function(item): + filtered_list.insert(insert_index, item) + insert_index += 1 + return filtered_list + + +def map(function, list_of_items): + mapped_list: list = [] + for index, item in enumerate(list_of_items): + mapped_list.insert(index, function(item)) + return mapped_list + + +def foldl( + function: Callable, list_of_items: list[int | str], initial: int | str +) -> int | str: + result: int | str = initial + if len(list_of_items) == 0: + return result + for index in range(0, len(list_of_items)): + result = function(result, list_of_items[index]) + return result + + +def foldr(function: Callable, list_of_items: list, initial: int | str) -> int | str: + result: int | str = initial + if len(list_of_items) == 0: + return result + for index in range(len(list_of_items) - 1, -1, -1): + result = function(result, list_of_items[index]) + return result + + +# reverse the order of the elements in the list +def reverse(list_of_items: list) -> list: + # not doing this + # return list[::-1] + reversed_list: list = [] + for item in list_of_items: + reversed_list.insert(0, item) + return reversed_list diff --git a/python/list-ops/list_ops_test.py b/python/list-ops/list_ops_test.py new file mode 100644 index 0000000..ea0d213 --- /dev/null +++ b/python/list-ops/list_ops_test.py @@ -0,0 +1,102 @@ +# These tests are auto-generated with test data from: +# https://github.com/exercism/problem-specifications/tree/main/exercises/list-ops/canonical-data.json +# File last updated on 2023-07-19 + +import unittest + +from list_ops import ( + append, + concat, + foldl, + foldr, + length, + reverse, + filter as list_ops_filter, + map as list_ops_map, +) + + +class ListOpsTest(unittest.TestCase): + def test_append_empty_lists(self): + self.assertEqual(append([], []), []) + + def test_append_list_to_empty_list(self): + self.assertEqual(append([], [1, 2, 3, 4]), [1, 2, 3, 4]) + + def test_append_empty_list_to_list(self): + self.assertEqual(append([1, 2, 3, 4], []), [1, 2, 3, 4]) + + def test_append_non_empty_lists(self): + self.assertEqual(append([1, 2], [2, 3, 4, 5]), [1, 2, 2, 3, 4, 5]) + + def test_concat_empty_list(self): + self.assertEqual(concat([]), []) + + def test_concat_list_of_lists(self): + self.assertEqual(concat([[1, 2], [3], [], [4, 5, 6]]), [1, 2, 3, 4, 5, 6]) + + def test_concat_list_of_nested_lists(self): + self.assertEqual( + concat([[[1], [2]], [[3]], [[]], [[4, 5, 6]]]), + [[1], [2], [3], [], [4, 5, 6]], + ) + + def test_filter_empty_list(self): + self.assertEqual(list_ops_filter(lambda x: x % 2 == 1, []), []) + + def test_filter_non_empty_list(self): + self.assertEqual(list_ops_filter(lambda x: x % 2 == 1, [1, 2, 3, 5]), [1, 3, 5]) + + def test_length_empty_list(self): + self.assertEqual(length([]), 0) + + def test_length_non_empty_list(self): + self.assertEqual(length([1, 2, 3, 4]), 4) + + def test_map_empty_list(self): + self.assertEqual(list_ops_map(lambda x: x + 1, []), []) + + def test_map_non_empty_list(self): + self.assertEqual(list_ops_map(lambda x: x + 1, [1, 3, 5, 7]), [2, 4, 6, 8]) + + def test_foldl_empty_list(self): + self.assertEqual(foldl(lambda acc, el: el * acc, [], 2), 2) + + def test_foldl_direction_independent_function_applied_to_non_empty_list(self): + self.assertEqual(foldl(lambda acc, el: el + acc, [1, 2, 3, 4], 5), 15) + + def test_foldl_direction_dependent_function_applied_to_non_empty_list(self): + self.assertEqual(foldl(lambda acc, el: el / acc, [1, 2, 3, 4], 24), 64) + + def test_foldr_empty_list(self): + self.assertEqual(foldr(lambda acc, el: el * acc, [], 2), 2) + + def test_foldr_direction_independent_function_applied_to_non_empty_list(self): + self.assertEqual(foldr(lambda acc, el: el + acc, [1, 2, 3, 4], 5), 15) + + def test_foldr_direction_dependent_function_applied_to_non_empty_list(self): + self.assertEqual(foldr(lambda acc, el: el / acc, [1, 2, 3, 4], 24), 9) + + def test_reverse_empty_list(self): + self.assertEqual(reverse([]), []) + + def test_reverse_non_empty_list(self): + self.assertEqual(reverse([1, 3, 5, 7]), [7, 5, 3, 1]) + + def test_reverse_list_of_lists_is_not_flattened(self): + self.assertEqual( + reverse([[1, 2], [3], [], [4, 5, 6]]), [[4, 5, 6], [], [3], [1, 2]] + ) + + # Additional tests for this track + + def test_foldr_foldr_add_string(self): + self.assertEqual( + foldr( + lambda acc, el: el + acc, ["e", "x", "e", "r", "c", "i", "s", "m"], "!" + ), + "exercism!", + ) + + def test_reverse_reverse_mixed_types(self): + self.assertEqual(reverse(["xyz", 4.0, "cat", 1]), [1, "cat", 4.0, "xyz"]) diff --git a/python/little-sisters-essay/.exercism/config.json b/python/little-sisters-essay/.exercism/config.json new file mode 100644 index 0000000..5049238 --- /dev/null +++ b/python/little-sisters-essay/.exercism/config.json @@ -0,0 +1,22 @@ +{ + "authors": [ + "kimolivia" + ], + "contributors": [ + "valentin-p", + "BethanyG" + ], + "files": { + "solution": [ + "string_methods.py" + ], + "test": [ + "string_methods_test.py" + ], + "exemplar": [ + ".meta/exemplar.py" + ] + }, + "icon": "anagrams", + "blurb": "Learn about string methods while improving your little sister's school essay." +} diff --git a/python/little-sisters-essay/.exercism/metadata.json b/python/little-sisters-essay/.exercism/metadata.json new file mode 100644 index 0000000..49dbe41 --- /dev/null +++ b/python/little-sisters-essay/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"little-sisters-essay","id":"a4c59f9f2679433e9c352c6cc98beefc","url":"https://exercism.org/tracks/python/exercises/little-sisters-essay","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/little-sisters-essay/HELP.md b/python/little-sisters-essay/HELP.md new file mode 100644 index 0000000..7a9f2f2 --- /dev/null +++ b/python/little-sisters-essay/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +
+ +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit string_methods.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/little-sisters-essay/HINTS.md b/python/little-sisters-essay/HINTS.md new file mode 100644 index 0000000..a7464f4 --- /dev/null +++ b/python/little-sisters-essay/HINTS.md @@ -0,0 +1,29 @@ +# Hints + +## General + +- [Python Documentation: String Methods][string-method-docs] +- [Python Documentation Tutorial: Text][tutorial-strings] + +## 1. Capitalize the title of the paper + +- You can use [string methods][title-method-docs] to capitalize the title properly. + +## 2. Check if each sentence ends with a period + +- You can use [string methods][endswith-method-docs] to check the ending of a string. + +## 3. Clean up spacing + +- You can use [string methods][strip-method-docs] to remove whitespace. + +## 4. Replace words with a synonym + +- You can use [string methods][replace-method-docs] to replace words. + +[endswith-method-docs]: https://docs.python.org/3/library/stdtypes.html#str.endswith +[replace-method-docs]: https://docs.python.org/3/library/stdtypes.html#str.replace +[string-method-docs]: https://docs.python.org/3/library/stdtypes.html#string-methods +[strip-method-docs]: https://docs.python.org/3/library/stdtypes.html#str.strip +[title-method-docs]: https://docs.python.org/3/library/stdtypes.html#str.title +[tutorial-strings]: https://docs.python.org/3/tutorial/introduction.html#text \ No newline at end of file diff --git a/python/little-sisters-essay/README.md b/python/little-sisters-essay/README.md new file mode 100644 index 0000000..db70aeb --- /dev/null +++ b/python/little-sisters-essay/README.md @@ -0,0 +1,194 @@ +# Little Sister's Essay + +Welcome to Little Sister's Essay on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. +If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :) + +## Introduction + +The `str` class offers [many useful methods][str methods] for working with and composing strings. +These include searching, cleaning, splitting, transforming, translating, and many other techniques. + +Strings are [immutable sequences][text sequence] of [Unicode code points][unicode code points] -- individual "characters" or code points (_strings of length 1_) can be referenced by `0-based index` number from the left, or `-1-based index` number from the right. + +Strings can be iterated through using `for item in ` or `for index, item in enumerate()` syntax. +They can be concatenated using the `+` operator or via `.join()` and implement all [common sequence operations][common sequence operations]. + +Strings are _immutable_, meaning the value of a `str` object in memory cannot change. +Functions or methods that operate on a `str` (_like the ones we are learning about here_) will return a new `instance` of that `str` object instead of modifying the original `str`. + +Following is a small selection of Python string methods. +For a complete list, see the [str class][str methods] in the Python docs. + + +[`.title()`][str-title] parses a string and capitalizes the first "character" of each "word" found. +In Python, this is very dependent on the [language codec][codecs] used and how the particular language represents words and characters. +There may also be [locale][locale] rules in place for a language or character set. + + +```python +man_in_hat_th = 'ผู้ชายใส่หมวก' +man_in_hat_ru = 'мужчина в шляпе' +man_in_hat_ko = '모자를 쓴 남자' +man_in_hat_en = 'the man in the hat.' + +>>> man_in_hat_th.title() +'ผู้ชายใส่หมวก' + +>>> man_in_hat_ru.title() +'Мужчина В Шляпе' + +>>> man_in_hat_ko.title() +'모자를 쓴 남자' + +>> man_in_hat_en.title() +'The Man In The Hat.' +``` + +[`.endswith()`][str-endswith] returns `True` if the string ends with ``, `False` otherwise. + + +```python +>>> 'My heart breaks. 💔'.endswith('💔') +True + +>>> 'cheerfulness'.endswith('ness') +True + +# Punctuation is part of the string, so needs to be included in any endswith match. +>>> 'Do you want to 💃?'.endswith('💃') +False + +>> 'The quick brown fox jumped over the lazy dog.'.endswith('dog') +False +``` + +[`.strip()`][str-strip] returns a copy of the `str` with leading and trailing `` removed. +The code points specified in `` are not a prefix or suffix - **all combinations** of the code points will be removed starting from **both ends** of the string. + If nothing is specified for ``, all combinations of whitespace code points will be removed. + + + ```python +# This will remove "https://", because it can be formed from "/stph:". +>>> 'https://unicode.org/emoji/'.strip('/stph:') +'unicode.org/emoji' + +# Removal of all whitespace from both ends of the str. +>>> ' 🐪🐪🐪🌟🐪🐪🐪 '.strip() +'🐪🐪🐪🌟🐪🐪🐪' + +>>> justification = 'оправдание' +>>> justification.strip('еина') +'оправд' + +# Prefix and suffix in one step. +>>> 'unaddressed'.strip('dnue') +'address' + +>>> ' unaddressed '.strip('dnue ') +'address' +``` + + +[`.replace(, )`][str-replace] returns a copy of the string with all occurrences of `` replaced with ``. + +The quote used below is from [The Hunting of the Snark][The Hunting of the Snark] by [Lewis Carroll][Lewis Carroll] + +```python +# The Hunting of the Snark, by Lewis Carroll +>>> quote = ''' +"Just the place for a Snark!" the Bellman cried, + As he landed his crew with care; +Supporting each man on the top of the tide + By a finger entwined in his hair. + +"Just the place for a Snark! I have said it twice: + That alone should encourage the crew. +Just the place for a Snark! I have said it thrice: + What I tell you three times is true." +''' + +>>> quote.replace('Snark', '🐲') +... +'\n"Just the place for a 🐲!" the Bellman cried,\n As he landed his crew with care;\nSupporting each man on the top of the tide\n By a finger entwined in his hair.\n\n"Just the place for a 🐲! I have said it twice:\n That alone should encourage the crew.\nJust the place for a 🐲! I have said it thrice:\n What I tell you three times is true."\n' + +>>> 'bookkeeper'.replace('kk', 'k k') +'book keeper' +``` + +[Lewis Carroll]: https://www.poetryfoundation.org/poets/lewis-carroll +[The Hunting of the Snark]: https://www.poetryfoundation.org/poems/43909/the-hunting-of-the-snark +[codecs]: https://docs.python.org/3/library/codecs.html +[common sequence operations]: https://docs.python.org/3/library/stdtypes.html#text-sequence-type-str +[locale]: https://docs.python.org/3/library/locale.html#module-locale +[str methods]: https://docs.python.org/3/library/stdtypes.html#string-methods +[str-endswith]: https://docs.python.org/3/library/stdtypes.html#str.endswith +[str-replace]: https://docs.python.org/3/library/stdtypes.html#str.replace +[str-strip]: https://docs.python.org/3/library/stdtypes.html#str.strip +[str-title]: https://docs.python.org/3/library/stdtypes.html#str.title +[text sequence]: https://docs.python.org/3/library/stdtypes.html#text-sequence-type-str +[unicode code points]: https://stackoverflow.com/questions/27331819/whats-the-difference-between-a-character-a-code-point-a-glyph-and-a-grapheme + +## Instructions + +In this exercise you are helping your younger sister edit her paper for school. The teacher is looking for correct punctuation, grammar, and excellent word choice. + +You have four tasks to clean up and modify strings. + +## 1. Capitalize the title of the paper + +Any good paper needs a properly formatted title. +Implement the function `capitalize_title()` which takes a title `str` as a parameter and capitalizes the first letter of each word. +This function should return a `str` in title case. + + +```python +>>> capitalize_title("my hobbies") +"My Hobbies" +``` + +## 2. Check if each sentence ends with a period + +You want to make sure that the punctuation in the paper is perfect. +Implement the function `check_sentence_ending()` that takes `sentence` as a parameter. This function should return a `bool`. + + +```python +>>> check_sentence_ending("I like to hike, bake, and read.") +True +``` + +## 3. Clean up spacing + +To make the paper look professional, unnecessary spacing needs to be removed. +Implement the function `clean_up_spacing()` that takes `sentence` as a parameter. +The function should remove extra whitespace at both the beginning and the end of the sentence, returning a new, updated sentence `str`. + + +```python +>>> clean_up_spacing(" I like to go on hikes with my dog. ") +"I like to go on hikes with my dog." +``` + +## 4. Replace words with a synonym + +To make the paper _even better_, you can replace some of the adjectives with their synonyms. +Write the function `replace_word_choice()` that takes `sentence`, `old_word`, and `new_word` as parameters. +This function should replace all instances of the `old_word` with the `new_word`, and return a new `str` with the updated sentence. + + +```python +>>> replace_word_choice("I bake good cakes.", "good", "amazing") +"I bake amazing cakes." +``` + +## Source + +### Created by + +- @kimolivia + +### Contributed to by + +- @valentin-p +- @BethanyG \ No newline at end of file diff --git a/python/little-sisters-essay/__pycache__/string_methods.cpython-313.pyc b/python/little-sisters-essay/__pycache__/string_methods.cpython-313.pyc new file mode 100644 index 0000000..d4a1934 Binary files /dev/null and b/python/little-sisters-essay/__pycache__/string_methods.cpython-313.pyc differ diff --git a/python/little-sisters-essay/__pycache__/string_methods.cpython-314.pyc b/python/little-sisters-essay/__pycache__/string_methods.cpython-314.pyc new file mode 100644 index 0000000..1ffa656 Binary files /dev/null and b/python/little-sisters-essay/__pycache__/string_methods.cpython-314.pyc differ diff --git a/python/little-sisters-essay/__pycache__/string_methods_test.cpython-313-pytest-8.3.4.pyc b/python/little-sisters-essay/__pycache__/string_methods_test.cpython-313-pytest-8.3.4.pyc new file mode 100644 index 0000000..bf2053d Binary files /dev/null and b/python/little-sisters-essay/__pycache__/string_methods_test.cpython-313-pytest-8.3.4.pyc differ diff --git a/python/little-sisters-essay/__pycache__/string_methods_test.cpython-314-pytest-9.1.0.pyc b/python/little-sisters-essay/__pycache__/string_methods_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..3d1fe47 Binary files /dev/null and b/python/little-sisters-essay/__pycache__/string_methods_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/little-sisters-essay/string_methods.py b/python/little-sisters-essay/string_methods.py new file mode 100644 index 0000000..dc64d52 --- /dev/null +++ b/python/little-sisters-essay/string_methods.py @@ -0,0 +1,39 @@ +"""Functions to help edit essay homework using string manipulation.""" + + +def capitalize_title(title): + """Convert the first letter of each word in the title to uppercase if needed. + + :param title: str - title string that needs title casing. + :return: str - title string in title case (first letters capitalized). + """ + return title.title() + + +def check_sentence_ending(sentence): + """Check the ending of the sentence to verify that a period is present. + + :param sentence: str - a sentence to check. + :return: bool - return True if punctuated correctly with period, False otherwise. + """ + return sentence[-1] == "." + + +def clean_up_spacing(sentence): + """Verify that there isn't any whitespace at the start and end of the sentence. + + :param sentence: str - a sentence to clean of leading and trailing space characters. + :return: str - a sentence that has been cleaned of leading and trailing space characters. + """ + return sentence.strip() + + +def replace_word_choice(sentence, old_word, new_word): + """Replace a word in the provided sentence with a new one. + + :param sentence: str - a sentence to replace words in. + :param old_word: str - word to replace. + :param new_word: str - replacement word. + :return: str - input sentence with new words in place of old words. + """ + return sentence.replace(old_word, new_word) diff --git a/python/little-sisters-essay/string_methods_test.py b/python/little-sisters-essay/string_methods_test.py new file mode 100644 index 0000000..9897314 --- /dev/null +++ b/python/little-sisters-essay/string_methods_test.py @@ -0,0 +1,98 @@ +import unittest +import pytest +from string_methods import (capitalize_title, + check_sentence_ending, + clean_up_spacing, + replace_word_choice) + + +class LittleSistersEssayTest(unittest.TestCase): + + @pytest.mark.task(taskno=1) + def test_capitalize_word(self): + + actual_result = capitalize_title("canopy") + expected = "Canopy" + error_message = (f'Called capitalize_title("canopy"). ' + f'The function returned "{actual_result}", ' + f'but the tests expected "{expected}" for the title.') + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=1) + def test_capitalize_title(self): + + actual_result = capitalize_title("fish are cold blooded") + expected = "Fish Are Cold Blooded" + error_message = (f'Called capitalize_title("fish are cold blooded"). ' + f'The function returned "{actual_result}", ' + f'but the tests expected "{expected}" for the title.') + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=2) + def test_sentence_ending(self): + + actual_result = check_sentence_ending("Snails can sleep for 3 years.") + expected = True + error_message = (f'Called check_sentence_ending("Snails can sleep for 3 years."). ' + f'The function returned {actual_result}, ' + f'but the tests expected {expected} for a period ending.') + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=2) + def test_sentence_ending_without_period(self): + + actual_result = check_sentence_ending("Fittonia are nice") + expected = False + error_message = (f'Called check_sentence_ending("Fittonia are nice"). ' + f'The function returned {actual_result}, ' + f'but the tests expected {expected} for a period ending.') + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=3) + def test_remove_extra_spaces_only_start(self): + + actual_result = clean_up_spacing(" A rolling stone gathers no moss") + expected = "A rolling stone gathers no moss" + error_message = (f'Called clean_up_spacing(" A rolling stone gathers no moss"). ' + f'The function returned "{actual_result}", ' + f'but the tests expected "{expected}" as a cleaned string.') + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=3) + def test_remove_extra_spaces(self): + + actual_result = clean_up_spacing(" Elephants can't jump. ") + expected = "Elephants can't jump." + error_message = ("Called clean_up_spacing(\" Elephants can't jump. \")" + f'The function returned "{actual_result}", ' + f'but the tests expected "{expected}" as a cleaned string.') + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=4) + def test_replace_word_choice(self): + + actual_result = replace_word_choice("Animals are cool.", "cool", "awesome") + expected = "Animals are awesome." + error_message = ('Called replace_word_choice("Animals are cool.", "cool", "awesome"). ' + f'The function returned "{actual_result}", ' + f'but the tests expected "{expected}" after the word replacement.') + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=4) + def test_replace_word_not_exist(self): + + actual_result = replace_word_choice("Animals are cool.", "small", "tiny") + expected = "Animals are cool." + error_message = ('Called replace_word_choice("Animals are cool.", "small", "tiny"). ' + f'The function returned "{actual_result}", ' + f'but the tests expected "{expected}", because the word ' + 'to be replaced is not in the sentence.') + + self.assertEqual(actual_result, expected, msg=error_message) diff --git a/python/little-sisters-vocab/.exercism/config.json b/python/little-sisters-vocab/.exercism/config.json new file mode 100644 index 0000000..2e1cd93 --- /dev/null +++ b/python/little-sisters-vocab/.exercism/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "aldraco", + "BethanyG" + ], + "files": { + "solution": [ + "strings.py" + ], + "test": [ + "strings_test.py" + ], + "exemplar": [ + ".meta/exemplar.py" + ] + }, + "icon": "two-fer", + "blurb": "Learn about strings by helping your little sister with her vocabulary homework." +} diff --git a/python/little-sisters-vocab/.exercism/metadata.json b/python/little-sisters-vocab/.exercism/metadata.json new file mode 100644 index 0000000..2e72b0f --- /dev/null +++ b/python/little-sisters-vocab/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"little-sisters-vocab","id":"6df0e15de087433caad67729067204a1","url":"https://exercism.org/tracks/python/exercises/little-sisters-vocab","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/little-sisters-vocab/HELP.md b/python/little-sisters-vocab/HELP.md new file mode 100644 index 0000000..67c4eaa --- /dev/null +++ b/python/little-sisters-vocab/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +<br> + +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit strings.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/little-sisters-vocab/HINTS.md b/python/little-sisters-vocab/HINTS.md new file mode 100644 index 0000000..dafc089 --- /dev/null +++ b/python/little-sisters-vocab/HINTS.md @@ -0,0 +1,37 @@ +# Hints + +## General + +- The Python Docs [Tutorial for strings][python-str-doc] has an overview of the Python `str` type. +- String methods [`str.join()`][str-join] and [`str.split()`][str-split] ar very helpful when processing strings. +- The Python Docs on [Sequence Types][common sequence operations] has a rundown of operations common to all sequences, including `strings`, `lists`, `tuples`, and `ranges`. + +There's four activities in the assignment, each with a set of text or words to work with. + +## 1. Add a prefix to a word + +- Small strings can be concatenated with the `+` operator. + +## 2. Add prefixes to word groups + +- Believe it or not, [`str.join()`][str-join] is all you need here. +- Like [`str.split()`][str-split]`, `str.join()` can take an arbitrary-length string, made up of any unicode code points. + +## 3. Remove a suffix from a word + +- Strings can be indexed or sliced from either the left (starting at 0) or the right (starting at -1). +- If you want the last code point of an arbitrary-length string, you can use [-1]. +- The last three letters in a string can be "sliced off" using a negative index. e.g. 'beautiful'[:-3] == 'beauti' + +## 4. Extract and transform a word + +- Using [`str.split()`][str-split] returns a `list` of strings broken on white space. +- `lists` are sequences, and can be indexed. +- [`str.split()`][str-split] can be directly indexed: `'Exercism rocks!'.split()[0] == 'Exercism'` +- Be careful of punctuation! Periods can be removed via slice: `'dark.'[:-1] == 'dark'` + + +[common sequence operations]: https://docs.python.org/3/library/stdtypes.html#text-sequence-type-str +[python-str-doc]: https://docs.python.org/3/tutorial/introduction.html#strings +[str-join]: https://docs.python.org/3/library/stdtypes.html#str.join +[str-split]: https://docs.python.org/3/library/stdtypes.html#str.split \ No newline at end of file diff --git a/python/little-sisters-vocab/README.md b/python/little-sisters-vocab/README.md new file mode 100644 index 0000000..1327736 --- /dev/null +++ b/python/little-sisters-vocab/README.md @@ -0,0 +1,340 @@ +# Little Sister's Vocabulary + +Welcome to Little Sister's Vocabulary on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. +If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :) + +## Introduction + +A `str` in Python is an [immutable sequence][text sequence] of [Unicode code points][unicode code points]. +These could include letters, diacritical marks, positioning characters, numbers, currency symbols, emoji, punctuation, space and line break characters, and more. + Being immutable, a `str` object's value in memory doesn't change; methods that appear to modify a string return a new copy or instance of that `str` object. + + +A `str` literal can be declared via single `'` or double `"` quotes. The escape `\` character is available as needed. + + +```python + +>>> single_quoted = 'These allow "double quoting" without "escape" characters.' + +>>> double_quoted = "These allow embedded 'single quoting', so you don't have to use an 'escape' character". + +>>> escapes = 'If needed, a \'slash\' can be used as an escape character within a string when switching quote styles won\'t work.' +``` + +Multi-line strings are declared with `'''` or `"""`. + + +```python +>>> triple_quoted = '''Three single quotes or "double quotes" in a row allow for multi-line string literals. + Line break characters, tabs and other whitespace are fully supported. + + You\'ll most often encounter these as "doc strings" or "doc tests" written just below the first line of a function or class definition. + They\'re often used with auto documentation ✍ tools. + ''' +``` + +Strings can be concatenated using the `+` operator. + This method should be used sparingly, as it is not very performant or easily maintained. + + +```python +language = "Ukrainian" +number = "nine" +word = "дев'ять" + +sentence = word + " " + "means" + " " + number + " in " + language + "." + +>>> print(sentence) +... +"дев'ять means nine in Ukrainian." +``` + +If a `list`, `tuple`, `set` or other collection of individual strings needs to be combined into a single `str`, [`<str>.join(<iterable>)`][str-join], is a better option: + + +```python +# str.join() makes a new string from the iterables elements. +>>> chickens = ["hen", "egg", "rooster"] +>>> ' '.join(chickens) +'hen egg rooster' + +# Any string can be used as the joining element. +>>> ' :: '.join(chickens) +'hen :: egg :: rooster' + +>>> ' 🌿 '.join(chickens) +'hen 🌿 egg 🌿 rooster' +``` + +Code points within a `str` can be referenced by `0-based index` number from the left: + + +```python +creative = '창의적인' + +>>> creative[0] +'창' + +>>> creative[2] +'적' + +>>> creative[3] +'인' +``` + +Indexing also works from the right, starting with a `-1-based index`: + + +```python +creative = '창의적인' + +>>> creative[-4] +'창' + +>>> creative[-2] +'적' + +>>> creative[-1] +'인' + +``` + + +There is no separate “character” or "rune" type in Python, so indexing a string produces a new `str` of length 1: + + +```python + +>>> website = "exercism" +>>> type(website[0]) +<class 'str'> + +>>> len(website[0]) +1 + +>>> website[0] == website[0:1] == 'e' +True +``` + +Substrings can be selected via _slice notation_, using [`<str>[<start>:stop:<step>]`][common sequence operations] to produce a new string. + Results exclude the `stop` index. + If no `start` is given, the starting index will be 0. + If no `stop` is given, the `stop` index will be the end of the string. + + +```python +moon_and_stars = '🌟🌟🌙🌟🌟⭐' +sun_and_moon = '🌞🌙🌞🌙🌞🌙🌞🌙🌞' + +>>> moon_and_stars[1:4] +'🌟🌙🌟' + +>>> moon_and_stars[:3] +'🌟🌟🌙' + +>>> moon_and_stars[3:] +'🌟🌟⭐' + +>>> moon_and_stars[:-1] +'🌟🌟🌙🌟🌟' + +>>> moon_and_stars[:-3] +'🌟🌟🌙' + +>>> sun_and_moon[::2] +'🌞🌞🌞🌞🌞' + +>>> sun_and_moon[:-2:2] +'🌞🌞🌞🌞' + +>>> sun_and_moon[1:-1:2] +'🌙🌙🌙🌙' +``` + +Strings can also be broken into smaller strings via [`<str>.split(<separator>)`][str-split], which will return a `list` of substrings. + The list can then be further indexed or split, if needed. + Using `<str>.split()` without any arguments will split the string on whitespace. + + +```python +>>> cat_ipsum = "Destroy house in 5 seconds mock the hooman." +>>> cat_ipsum.split() +... +['Destroy', 'house', 'in', '5', 'seconds', 'mock', 'the', 'hooman.'] + + +>>> cat_ipsum.split()[-1] +'hooman.' + + +>>> cat_words = "feline, four-footed, ferocious, furry" +>>> cat_words.split(', ') +... +['feline', 'four-footed', 'ferocious', 'furry'] +``` + + +Separators for `<str>.split()` can be more than one character. +The **whole string** is used for split matching. + + +```python + +>>> colors = """red, +orange, +green, +purple, +yellow""" + +>>> colors.split(',\n') +['red', 'orange', 'green', 'purple', 'yellow'] +``` + +Strings support all [common sequence operations][common sequence operations]. + Individual code points can be iterated through in a loop via `for item in <str>`. + Indexes _with_ items can be iterated through in a loop via `for index, item in enumerate(<str>)`. + + +```python + +>>> exercise = 'လေ့ကျင့်' + +# Note that there are more code points than perceived glyphs or characters +>>> for code_point in exercise: +... print(code_point) +... +လ +ေ +့ +က +ျ +င +် +့ + +# Using enumerate will give both the value and index position of each element. +>>> for index, code_point in enumerate(exercise): +... print(index, ": ", code_point) +... +0 : လ +1 : ေ +2 : ့ +3 : က +4 : ျ +5 : င +6 : ် +7 : ့ +``` + + +[common sequence operations]: https://docs.python.org/3/library/stdtypes.html#common-sequence-operations +[str-join]: https://docs.python.org/3/library/stdtypes.html#str.join +[str-split]: https://docs.python.org/3/library/stdtypes.html#str.split +[text sequence]: https://docs.python.org/3/library/stdtypes.html#text-sequence-type-str +[unicode code points]: https://stackoverflow.com/questions/27331819/whats-the-difference-between-a-character-a-code-point-a-glyph-and-a-grapheme + +## Instructions + +You are helping your younger sister with her English vocabulary homework, which she is finding very tedious. + Her class is learning to create new words by adding _prefixes_ and _suffixes_. + Given a set of words, the teacher is looking for correctly transformed words with correct spelling by adding the prefix to the beginning or the suffix to the ending. + +The assignment has four activities, each with a set of text or words to work with. + + +## 1. Add a prefix to a word + +One of the most common prefixes in English is `un`, meaning "not". + In this activity, your sister needs to make negative, or "not" words by adding `un` to them. + +Implement the `add_prefix_un(<word>)` function that takes `word` as a parameter and returns a new `un` prefixed word: + + +```python +>>> add_prefix_un("happy") +'unhappy' + +>>> add_prefix_un("manageable") +'unmanageable' +``` + + +## 2. Add prefixes to word groups + +There are four more common prefixes that your sister's class is studying: + `en` (_meaning to 'put into' or 'cover with'_), + `pre` (_meaning 'before' or 'forward'_), + `auto` (_meaning 'self' or 'same'_), + and `inter` (_meaning 'between' or 'among'_). + + In this exercise, the class is creating groups of vocabulary words using these prefixes, so they can be studied together. + Each prefix comes in a list with common words it's used with. + The students need to apply the prefix and produce a string that shows the prefix applied to all of the words. + +Implement the `make_word_groups(<vocab_words>)` function that takes a `vocab_words` as a parameter in the following form: + `[<prefix>, <word_1>, <word_2> .... <word_n>]`, and returns a string with the prefix applied to each word that looks like: + `'<prefix> :: <prefix><word_1> :: <prefix><word_2> :: <prefix><word_n>'`. + + +```python +>>> make_word_groups(['en', 'close', 'joy', 'lighten']) +'en :: enclose :: enjoy :: enlighten' + +>>> make_word_groups(['pre', 'serve', 'dispose', 'position']) +'pre :: preserve :: predispose :: preposition' + +>> make_word_groups(['auto', 'didactic', 'graph', 'mate']) +'auto :: autodidactic :: autograph :: automate' + +>>> make_word_groups(['inter', 'twine', 'connected', 'dependent']) +'inter :: intertwine :: interconnected :: interdependent' +``` + + +## 3. Remove a suffix from a word + +`ness` is a common suffix that means _'state of being'_. + In this activity, your sister needs to find the original root word by removing the `ness` suffix. + But of course there are pesky spelling rules: If the root word originally ended in a consonant followed by a 'y', then the 'y' was changed to 'i'. + Removing 'ness' needs to restore the 'y' in those root words. e.g. `happiness` --> `happi` --> `happy`. + +Implement the `remove_suffix_ness(<word>)` function that takes in a `word`, and returns the root word without the `ness` suffix. + + +```python +>>> remove_suffix_ness("heaviness") +'heavy' + +>>> remove_suffix_ness("sadness") +'sad' +``` + +## 4. Extract and transform a word + +Suffixes are often used to change the part of speech a word is assigned to. + A common practice in English is "verbing" or "verbifying" -- where an adjective _becomes_ a verb by adding an `en` suffix. + +In this task, your sister is going to practice "verbing" words by extracting an adjective from a sentence and turning it into a verb. + Fortunately, all the words that need to be transformed here are "regular" - they don't need spelling changes to add the suffix. + +Implement the `adjective_to_verb(<sentence>, <index>)` function that takes two parameters. + A `sentence` using the vocabulary word, and the `index` of the word, once that sentence is split apart. + The function should return the extracted adjective as a verb. + + +```python +>>> adjective_to_verb('I need to make that bright.', -1 ) +'brighten' + +>>> adjective_to_verb('It got dark as the sun set.', 2) +'darken' +``` + +## Source + +### Created by + +- @aldraco +- @BethanyG \ No newline at end of file diff --git a/python/little-sisters-vocab/__pycache__/strings.cpython-313.pyc b/python/little-sisters-vocab/__pycache__/strings.cpython-313.pyc new file mode 100644 index 0000000..2684be9 Binary files /dev/null and b/python/little-sisters-vocab/__pycache__/strings.cpython-313.pyc differ diff --git a/python/little-sisters-vocab/__pycache__/strings.cpython-314.pyc b/python/little-sisters-vocab/__pycache__/strings.cpython-314.pyc new file mode 100644 index 0000000..9d6f857 Binary files /dev/null and b/python/little-sisters-vocab/__pycache__/strings.cpython-314.pyc differ diff --git a/python/little-sisters-vocab/__pycache__/strings_test.cpython-313-pytest-8.3.4.pyc b/python/little-sisters-vocab/__pycache__/strings_test.cpython-313-pytest-8.3.4.pyc new file mode 100644 index 0000000..c47859d Binary files /dev/null and b/python/little-sisters-vocab/__pycache__/strings_test.cpython-313-pytest-8.3.4.pyc differ diff --git a/python/little-sisters-vocab/__pycache__/strings_test.cpython-313-pytest-8.3.5.pyc b/python/little-sisters-vocab/__pycache__/strings_test.cpython-313-pytest-8.3.5.pyc new file mode 100644 index 0000000..c47859d Binary files /dev/null and b/python/little-sisters-vocab/__pycache__/strings_test.cpython-313-pytest-8.3.5.pyc differ diff --git a/python/little-sisters-vocab/__pycache__/strings_test.cpython-314-pytest-9.1.0.pyc b/python/little-sisters-vocab/__pycache__/strings_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..11ca4ca Binary files /dev/null and b/python/little-sisters-vocab/__pycache__/strings_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/little-sisters-vocab/strings.py b/python/little-sisters-vocab/strings.py new file mode 100644 index 0000000..cced3bb --- /dev/null +++ b/python/little-sisters-vocab/strings.py @@ -0,0 +1,59 @@ +"""Functions for creating, transforming, and adding prefixes to strings.""" + + +def add_prefix_un(word): + """Take the given word and add the 'un' prefix. + + :param word: str - containing the root word. + :return: str - of root word prepended with 'un'. + """ + return "un" + word + + +def make_word_groups(vocab_words): + """Transform a list containing a prefix and words into a string with the prefix followed by the words with prefix prepended. + + :param vocab_words: list - of vocabulary words with prefix in first index. + :return: str - of prefix followed by vocabulary words with + prefix applied. + + This function takes a `vocab_words` list and returns a string + with the prefix and the words with prefix applied, separated + by ' :: '. + + For example: list('en', 'close', 'joy', 'lighten'), + produces the following string: 'en :: enclose :: enjoy :: enlighten'. + """ + result: str = vocab_words[0] + for word in vocab_words[1:]: + result += " :: " + vocab_words[0] + word + return result + + +def remove_suffix_ness(word): + """Remove the suffix from the word while keeping spelling in mind. + + :param word: str - of word to remove suffix from. + :return: str - of word with suffix removed & spelling adjusted. + + For example: "heaviness" becomes "heavy", but "sadness" becomes "sad". + """ + new_word: str = word[: len(word) - 4] + match new_word[-1]: + case "i": + return new_word[: len(new_word) - 1] + "y" + case _: + return new_word + + +def adjective_to_verb(sentence, index): + """Change the adjective within the sentence to a verb. + + :param sentence: str - that uses the word in sentence. + :param index: int - index of the word to remove and transform. + :return: str - word that changes the extracted adjective to a verb. + + For example, ("It got dark as the sun set.", 2) becomes "darken". + """ + word_to_transform: str = sentence.split(" ")[index] + return word_to_transform.strip(".,!?") + "en" diff --git a/python/little-sisters-vocab/strings_test.py b/python/little-sisters-vocab/strings_test.py new file mode 100644 index 0000000..b13d4e9 --- /dev/null +++ b/python/little-sisters-vocab/strings_test.py @@ -0,0 +1,126 @@ +import unittest +import pytest +from strings import (add_prefix_un, + make_word_groups, + remove_suffix_ness, + adjective_to_verb) + + +class LittleSistersVocabTest(unittest.TestCase): + + @pytest.mark.task(taskno=1) + def test_add_prefix_un(self): + input_data = ['happy', 'manageable', 'fold', 'eaten', 'avoidable', 'usual'] + result_data = [f'un{item}' for item in input_data] + + for variant, (word, expected) in enumerate(zip(input_data, result_data), start=1): + with self.subTest(f'variation #{variant}', word=word, expected=expected): + + actual_result = add_prefix_un(word) + error_message = (f'Called add_prefix_un("{word}"). ' + f'The function returned "{actual_result}", but the ' + f'tests expected "{expected}" after adding "un" as a prefix.') + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=2) + def test_make_word_groups_en(self): + input_data = ['en', 'circle', 'fold', 'close', 'joy', 'lighten', 'tangle', 'able', 'code', 'culture'] + expected = ('en :: encircle :: enfold :: enclose :: enjoy :: enlighten ::' + ' entangle :: enable :: encode :: enculture') + + actual_result = make_word_groups(input_data) + error_message = (f'Called make_word_groups({input_data}). ' + f'The function returned "{actual_result}", ' + f'but the tests expected "{expected}" for the ' + 'word groups.') + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=2) + def test_make_word_groups_pre(self): + input_data = ['pre', 'serve', 'dispose', 'position', 'requisite', 'digest', + 'natal', 'addressed', 'adolescent', 'assumption', 'mature', 'compute'] + expected = ('pre :: preserve :: predispose :: preposition :: prerequisite :: ' + 'predigest :: prenatal :: preaddressed :: preadolescent :: preassumption :: ' + 'premature :: precompute') + + actual_result = make_word_groups(input_data) + error_message = (f'Called make_word_groups({input_data}). ' + f'The function returned "{actual_result}", ' + f'but the tests expected "{expected}" for the ' + 'word groups.') + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=2) + def test_make_word_groups_auto(self): + input_data = ['auto', 'didactic', 'graph', 'mate', 'chrome', 'centric', 'complete', + 'echolalia', 'encoder', 'biography'] + expected = ('auto :: autodidactic :: autograph :: automate :: autochrome :: ' + 'autocentric :: autocomplete :: autoecholalia :: autoencoder :: ' + 'autobiography') + + actual_result = make_word_groups(input_data) + error_message = (f'Called make_word_groups({input_data}). ' + f'The function returned "{actual_result}", ' + f'but the tests expected "{expected}" for the ' + 'word groups.') + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=2) + def test_make_words_groups_inter(self): + input_data = ['inter', 'twine', 'connected', 'dependent', 'galactic', 'action', + 'stellar', 'cellular', 'continental', 'axial', 'operative', 'disciplinary'] + expected = ('inter :: intertwine :: interconnected :: interdependent :: ' + 'intergalactic :: interaction :: interstellar :: intercellular :: ' + 'intercontinental :: interaxial :: interoperative :: interdisciplinary') + + actual_result = make_word_groups(input_data) + error_message = (f'Called make_word_groups({input_data}). ' + f'The function returned "{actual_result}", ' + f'but the tests expected "{expected}" for the ' + 'word groups.') + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=3) + def test_remove_suffix_ness(self): + input_data = ['heaviness', 'sadness', 'softness', 'crabbiness', 'lightness', 'artiness', 'edginess'] + result_data = ['heavy', 'sad', 'soft', 'crabby', 'light', 'arty', 'edgy'] + + for variant, (word, expected) in enumerate(zip(input_data, result_data), start=1): + with self.subTest(f'variation #{variant}', word=word, expected=expected): + actual_result = remove_suffix_ness(word) + error_message = (f'Called remove_suffix_ness("{word}"). ' + f'The function returned "{actual_result}", ' + f'but the tests expected "{expected}" after the ' + 'suffix was removed.') + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=4) + def test_adjective_to_verb(self): + input_data = ['Look at the bright sky.', + 'His expression went dark.', + 'The bread got hard after sitting out.', + 'The butter got soft in the sun.', + 'Her eyes were light blue.', + 'The morning fog made everything damp with mist.', + 'He cut the fence pickets short by mistake.', + 'Charles made weak crying noises.', + 'The black oil got on the white dog.'] + index_data = [-2, -1, 3, 3, -2, -3, 5, 2, 1] + result_data = ['brighten', 'darken', 'harden', 'soften', + 'lighten', 'dampen', 'shorten', 'weaken', 'blacken'] + + for variant, (sentence, index, expected) in enumerate(zip(input_data, index_data, result_data), start=1): + with self.subTest(f'variation #{variant}', sentence=sentence, index=index, expected=expected): + actual_result = adjective_to_verb(sentence, index) + error_message = (f'Called adjective_to_verb("{sentence}", {index}). ' + f'The function returned "{actual_result}", but the tests ' + f'expected "{expected}" as the verb for ' + f'the word at index {index}.') + + self.assertEqual(actual_result, expected, msg=error_message) diff --git a/python/locomotive-engineer/.exercism/config.json b/python/locomotive-engineer/.exercism/config.json new file mode 100644 index 0000000..e9110e9 --- /dev/null +++ b/python/locomotive-engineer/.exercism/config.json @@ -0,0 +1,25 @@ +{ + "authors": [ + "meatball133", + "BethanyG" + ], + "contributors": [ + "IsaacG" + ], + "files": { + "solution": [ + "locomotive_engineer.py" + ], + "test": [ + "locomotive_engineer_test.py" + ], + "exemplar": [ + ".meta/exemplar.py" + ] + }, + "forked_from": [ + "javascript/train-driver" + ], + "icon": "tracks-on-tracks-on-tracks", + "blurb": "Learn about unpacking and multiple assignment in Python while helping Linus with his train control system." +} diff --git a/python/locomotive-engineer/.exercism/metadata.json b/python/locomotive-engineer/.exercism/metadata.json new file mode 100644 index 0000000..34182b4 --- /dev/null +++ b/python/locomotive-engineer/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"locomotive-engineer","id":"2b97ea96693c48de834541d3b8b3d18b","url":"https://exercism.org/tracks/python/exercises/locomotive-engineer","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/locomotive-engineer/HELP.md b/python/locomotive-engineer/HELP.md new file mode 100644 index 0000000..a7b9d0a --- /dev/null +++ b/python/locomotive-engineer/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +<br> + +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit locomotive_engineer.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/locomotive-engineer/HINTS.md b/python/locomotive-engineer/HINTS.md new file mode 100644 index 0000000..ff79489 --- /dev/null +++ b/python/locomotive-engineer/HINTS.md @@ -0,0 +1,34 @@ +# Hints + +## General + +- To extract multiple arguments in the function parameters so can you pack them with the `*args` operator for `list` or `tuples` or `**kwargs` for keyword-based arguments. +- To pack or unpack use the `*` or `**` operator. + +## 1. Create a list of all wagons + +- Multiple arguments in the function parameters can be packed with the `*args` operator. + +## 2. Fix list of wagons + +- Using unpacking with the `*` operator, lets you extract the first two elements of a `list` while keeping the rest intact. +- To add another `list` into an existing `list`, you can use the `*` operator to "spread" the `list`. + +## 3. Add missing stops + +- Using `**kwargs` as a function parameter will allow an arbitrary number of keyword arguments to be passed. +- Using `**<dict>` as an argument will unpack a dictionary into keyword arguments. +- You can put keyword arguments in a `{}` or `dict()`. +- To get the values out of a dictionary, you can use the `<dict>.values()` method. + +## 4. Extend routing information + +- Using `**<dict>` as an argument will unpack a dictionary into keyword arguments. +- You can put keyword arguments in a `{}` or `dict()`. + +## 5. Fix the wagon depot + +- `zip(*iterators)` can use used to transpose a nested `list`. +- To extract data from zipped iterators, you can use a for loop. +- you can also unpack zipped iterators using `*`. + `[*content] = zip(iterator_1, iterator_2)` will unzip the `tuple` produced by `zip()` into a `list`. \ No newline at end of file diff --git a/python/locomotive-engineer/README.md b/python/locomotive-engineer/README.md new file mode 100644 index 0000000..9b4a21c --- /dev/null +++ b/python/locomotive-engineer/README.md @@ -0,0 +1,504 @@ +# Locomotive Engineer + +Welcome to Locomotive Engineer on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. +If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :) + +## Introduction + +Unpacking refers to the act of extracting the elements of a collection, such as a `list`, `tuple`, or `dict`, using iteration. +Unpacked values can then be assigned to variables within the same statement, which is commonly referred to as [Multiple assignment][multiple assignment]. + +The special operators `*` and `**` are often used in unpacking contexts and with multiple assignment. + +~~~~exercism/caution +`*<variable_name>` and `**<variable_name>` should not be confused with `*` and `**`. While `*` and `**` are used for multiplication and exponentiation respectively, `*<variable_name>` and `**<variable_name>` are used as packing and unpacking operators. +~~~~ + + +## Multiple assignment + +In multiple assignment, the number of variables on the left side of the assignment operator (`=`) must match the number of values on the right side. +To separate the values, use a comma `,`: + +```python +>>> a, b = 1, 2 +>>> a +1 +``` + +If the multiple assignment gets an incorrect number of variables for the values given, a `ValueError` will be thrown: + +```python +>>> x, y, z = 1, 2 + +ValueError: too many values to unpack (expected 3, got 2) +``` + +Multiple assignment is not limited to one data type: + +```python +>>> x, y, z = 1, "Hello", True +>>> x +1 + +>>> y +'Hello' + +>>> z +True +``` + +Multiple assignment can be used to swap elements in `lists`. +This practice is pretty common in [sorting algorithms][sorting algorithms]. +For example: + +```python +>>> numbers = [1, 2] +>>> numbers[0], numbers[1] = numbers[1], numbers[0] +>>> numbers +[2, 1] +``` + +Since `tuples` are immutable, you can't swap elements in a `tuple`. + + +## Unpacking + +~~~~exercism/note +The examples below use `lists` but the same concepts apply to `tuples`. +~~~~ + +In Python, it is possible to [unpack the elements of `list`/`tuple`/`dictionary`][unpacking] into distinct variables. +Since values appear within `lists`/`tuples` in a specific order, they are unpacked into variables in the same order: + +```python +>>> fruits = ["apple", "banana", "cherry"] +>>> x, y, z = fruits +>>> x +"apple" +``` + +If there are values that are not needed then you can use `_` to flag them: + +```python +>>> fruits = ["apple", "banana", "cherry"] +>>> _, _, z = fruits +>>> z +"cherry" +``` + + +### Deep unpacking + +Unpacking and assigning values from a `list`/`tuple` enclosed inside a `list` or `tuple` (_also known as nested lists/tuples_) works in the same way a shallow unpacking does — but often needs qualifiers to clarify the context or position: + +```python +>>> fruits_vegetables = [["apple", "banana"], ["carrot", "potato"]] +>>> [[a, b], [c, d]] = fruits_vegetables +>>> a +"apple" + +>>> d +"potato" +``` + +You can also deeply unpack just a portion of a nested `list`/`tuple`: + +```python +>>> fruits_vegetables = [["apple", "banana"], ["carrot", "potato"]] +>>> [a, [c, d]] = fruits_vegetables +>>> a +["apple", "banana"] + +>>> c +"carrot" +``` + +If the unpacking has variables with incorrect placement and/or an incorrect number of values, you will get a `ValueError`: + +```python +>>> fruits_vegetables = [["apple", "banana"], ["carrot", "potato"]] +>>> [[a, b], [d]] = fruits_vegetables + +ValueError: too many values to unpack (expected 1) +``` + +### Unpacking a list/tuple with `*` + +When [unpacking a `list`/`tuple`][packing and unpacking] you can use the `*` operator to capture the "leftover" values. +This is clearer than slicing the `list`/`tuple` (_which in some situations is less readable_). +For example, the first element can be extracted and then the remaining values can be placed into a new `list` without the first element: + +```python +>>> fruits = ["apple", "banana", "cherry", "orange", "kiwi", "melon", "mango"] +>>> x, *last = fruits +>>> x +"apple" + +>>> last +["banana", "cherry", "orange", "kiwi", "melon", "mango"] +``` + +We can also extract the values at the beginning and end of the `list` while grouping all the values in the middle: + +```python +>>> fruits = ["apple", "banana", "cherry", "orange", "kiwi", "melon", "mango"] +>>> x, *middle, y, z = fruits +>>> y +"melon" + +>>> middle +["banana", "cherry", "orange", "kiwi"] +``` + +We can also use `*` in deep unpacking: + +```python +>>> fruits_vegetables = [["apple", "banana", "melon"], ["carrot", "potato", "tomato"]] +>>> [[a, *rest], b] = fruits_vegetables +>>> a +"apple" + +>>> rest +["banana", "melon"] +``` + +### Unpacking a dictionary + +[Unpacking a dictionary][packing and unpacking] is a bit different from unpacking a `list`/`tuple`. +Iteration over dictionaries defaults to the **keys**. +So when unpacking a `dict`, you can only unpack the **keys** and not the **values**: + +```python +>>> fruits_inventory = {"apple": 6, "banana": 2, "cherry": 3} +>>> x, y, z = fruits_inventory +>>> x +"apple" +``` + +If you want to unpack the values then you can use the `<dict>.values()` method: + +```python +>>> fruits_inventory = {"apple": 6, "banana": 2, "cherry": 3} +>>> x, y, z = fruits_inventory.values() +>>> x +6 +``` + +If both **keys** and **values** are needed, use the [`<dict>.items()`][items] method. +`<dict>.items()` generates an [iterable view][view-objects] containing **key-value** pairs. +These can be unpacked into a `tuple`: + +```python +>>> fruits_inventory = {"apple": 6, "banana": 2, "cherry": 3} +>>> x, y, z = fruits_inventory.items() +>>> x +("apple", 6) +``` + +## Packing + +[Packing][packing and unpacking] is the ability to group multiple values into one `list` that is assigned to a variable. +This is useful when you want to _unpack_ values, make changes, and then _pack_ the results back into a variable. +It also makes it possible to perform merges on 2 or more `lists`/`tuples`/`dicts`. + +### Packing a list/tuple with `*` + +Packing a `list`/`tuple` can be done using the `*` operator. +This will pack all the values into a `list`/`tuple`. + +```python +>>> fruits = ("apple", "banana", "cherry") +>>> more_fruits = ["orange", "kiwi", "melon", "mango"] + +# fruits and more_fruits are unpacked and then their elements are packed into combined_fruits +>>> combined_fruits = *fruits, *more_fruits + +# If there is no * on to the left of the "=" the result is a tuple +>>> combined_fruits +("apple", "banana", "cherry", "orange", "kiwi", "melon", "mango") + +# If the * operator is used on the left side of "=" the result is a list. +# Note the trailing comma. +>>> *combined_fruits_too, = *fruits, *more_fruits +>>> combined_fruits_too +['apple', 'banana', 'cherry', 'orange', 'kiwi', 'melon', 'mango'] +``` + +For more background on using `*` on the left-hand side, see [PEP 3132][pep-3132]. + + +### Packing a dictionary with `**` + +Packing a dictionary is done by using the `**` operator. +This will pack all **key**-**value** pairs from one dictionary into another dictionary, or combine two dictionaries together. + +```python +>>> fruits_inventory = {"apple": 6, "banana": 2, "cherry": 3} +>>> more_fruits_inventory = {"orange": 4, "kiwi": 1, "melon": 2, "mango": 3} + +# fruits_inventory and more_fruits_inventory are unpacked into key-values pairs and combined. +>>> combined_fruits_inventory = {**fruits_inventory, **more_fruits_inventory} + +# then the pairs are packed into combined_fruits_inventory +>>> combined_fruits_inventory +{"apple": 6, "banana": 2, "cherry": 3, "orange": 4, "kiwi": 1, "melon": 2, "mango": 3} +``` + +## Usage of `*` and `**` with functions + +### Packing with function parameters + +When you create a function that accepts an arbitrary number of arguments, you can use [`*args` or `**kwargs`][args and kwargs] in the function definition. +`*args` is used to pack an arbitrary number of positional (_non-keyword_) arguments as a `tuple` and +`**kwargs` is used to pack an arbitrary number of keyword arguments as a dictionary. + +Usage of `*args`: + +```python +# This function is defined to take any number of positional arguments + +>>> def my_function(*args): +... print(args) + +# Arguments given to the function are packed into a tuple + +>>> my_function(1, 2, 3) +(1, 2, 3) + +>>> my_function("Hello") +("Hello") + +>>> my_function(1, 2, 3, "Hello", "Mars") +(1, 2, 3, "Hello", "Mars") +``` + +Usage of `**kwargs`: + +```python +# This function is defined to take any number of keyword arguments + +>>> def my_function(**kwargs): +... print(kwargs) + +# Arguments given to the function are packed into a dictionary + +>>> my_function(a=1, b=2, c=3) +{"a": 1, "b": 2, "c": 3} +``` + +`*args` and `**kwargs` can also be used in combination with one another: + +```python +>>> def my_function(*args, **kwargs): +... print(sum(args)) +... for key, value in kwargs.items(): +... print(str(key) + " = " + str(value)) + +>>> my_function(1, 2, 3, a=1, b=2, c=3) +6 +a = 1 +b = 2 +c = 3 +``` + +You can also write parameters before `*args` to allow for specific positional arguments. +Individual keyword arguments then have to appear before `**kwargs`. + +~~~~exercism/caution +[Arguments have to be structured](https://www.python-engineer.com/courses/advancedpython/18-function-arguments/) like this: + +`def my_function(<positional_args>, *args, <key-word_args>, **kwargs)` + +If you don't follow this order then you will get an error. +~~~~ + +```python +>>> def my_function(a, b, *args): +... print(a) +... print(b) +... print(args) + +>>> my_function(1, 2, 3, 4, 5) +1 +2 +(3, 4, 5) +``` + +Writing arguments in an incorrect order will result in an error: + +```python +>>>def my_function(*args, a, b): +... print(args) + +>>>my_function(1, 2, 3, 4, 5) +Traceback (most recent call last): + File "c:\something.py", line 3, in <module> + my_function(1, 2, 3, 4, 5) +TypeError: my_function() missing 2 required keyword-only arguments: 'a' and 'b' +``` + +### Unpacking into function calls + +You can use `*` to unpack a `list`/`tuple` of arguments into a function call. +This is very useful for functions that don't accept an `iterable`: + +```python +>>> def my_function(a, b, c): +... print(c) +... print(b) +... print(a) + +numbers = [1, 2, 3] +>>> my_function(*numbers) +3 +2 +1 +``` + +Using `*` unpacking with the `zip()` function is another common use case. +Since `zip()` takes multiple iterables and returns a `list` of `tuples` with the values from each `iterable` grouped: + +```python +>>> values = (['x', 'y', 'z'], [1, 2, 3], [True, False, True]) +>>> a, *rest = zip(*values) +>>> rest +[('y', 2, False), ('z', 3, True)] +``` + +[args and kwargs]: https://www.geeksforgeeks.org/args-kwargs-python/ +[items]: https://docs.python.org/3/library/stdtypes.html#dict.items +[multiple assignment]: https://www.geeksforgeeks.org/assigning-multiple-variables-in-one-line-in-python/ +[packing and unpacking]: https://www.geeksforgeeks.org/packing-and-unpacking-arguments-in-python/ +[pep-3132]: https://peps.python.org/pep-3132/ +[sorting algorithms]: https://realpython.com/sorting-algorithms-python/ +[unpacking]: https://www.geeksforgeeks.org/unpacking-arguments-in-python/?ref=rp +[view-objects]: https://docs.python.org/3/library/stdtypes.html#dict-views + +## Instructions + +Your friend Linus is a Locomotive Engineer who drives cargo trains between cities. +Although they are amazing at handling trains, they are not amazing at handling logistics or computers. +They would like to enlist your programming help organizing train details and correcting mistakes in route data. + +~~~~exercism/note +This exercise could easily be solved using slicing, indexing, and various `dict` methods. +However, we would like you to practice packing, unpacking, and multiple assignment in solving each of the tasks below. +~~~~ + +## 1. Create a list of all wagons + +Your friend has been keeping track of each wagon identifier (ID), but they are never sure how many wagons the system is going to have to process at any given time. It would be much easier for the rest of the logistics program to have this data packaged into a unified `list`. + +Implement a function `get_list_of_wagons()` that accepts an arbitrary number of wagon IDs. +Each ID will be a positive integer. +The function should then `return` the given IDs as a single `list`. + +```python +>>> get_list_of_wagons(1, 7, 12, 3, 14, 8, 5) +[1, 7, 12, 3, 14, 8, 5] +``` + +## 2. Fix the list of wagons + +At this point, you are starting to get a feel for the data and how it's used in the logistics program. +The ID system always assigns the locomotive an ID of **1**, with the remainder of the wagons in the train assigned a randomly chosen ID greater than **1**. + +Your friend had to connect two new wagons to the train and forgot to update the system! +Now, the first two wagons in the train `list` have to be moved to the end, or everything will be out of order. + +To make matters more complicated, your friend just uncovered a second `list` that appears to contain missing wagon IDs. +All they can remember is that once the new wagons are moved, the IDs from this second `list` should be placed directly after the designated locomotive. + +Linus would be really grateful to you for fixing their mistakes and consolidating the data. + +Implement a function `fix_list_of_wagons()` that takes two `lists` containing wagon IDs. +It should reposition the first two items of the first `list` to the end, and insert the values from the second `list` behind (_on the right hand side of_) the locomotive ID (**1**). +The function should then `return` a `list` with the modifications. + +```python +>>> fix_list_of_wagons([2, 5, 1, 7, 4, 12, 6, 3, 13], [3, 17, 6, 15]) +[1, 3, 17, 6, 15, 7, 4, 12, 6, 3, 13, 2, 5] +``` + +## 3. Add missing stops + +Now that all the wagon data is correct, Linus would like you to update the system's routing information. +Along a transport route, a train might make stops at a few different stations to pick up and/or drop off cargo. +Each journey could have a different number of these intermediary delivery points. +Your friend would like you to update the systems routing `dict` with any missing/additional delivery information. + +Implement a function `add_missing_stops()` that accepts a routing `dict` followed by a variable number of keyword arguments. +These arguments could be in the form of a `dict` holding one or more stops, or any number of `stop_number=city` keyword pairs. +Your function should then return the routing `dict` updated with an additional `key` that holds a `list` of all the added stops in order. + +```python +>>> add_missing_stops({"from": "New York", "to": "Miami"}, + stop_1="Washington, DC", stop_2="Charlotte", stop_3="Atlanta", + stop_4="Jacksonville", stop_5="Orlando") + +{"from": "New York", "to": "Miami", "stops": ["Washington, DC", "Charlotte", "Atlanta", "Jacksonville", "Orlando"]} +``` + +## 4. Extend routing information + +Linus has been working on the routing program and has noticed that certain routes are missing some important details. +Initial route information has been constructed as a `dict` and your friend would like you to update that `dict` with whatever might be missing. +Every route in the system requires slightly different details, so Linus would really prefer a generic solution. + +Implement a function called `extend_route_information()` that accepts two `dicts`. +The first `dict` contains the origin and destination cities the train route runs between. + +The second `dict` contains other routing details such as train speed, length, or temperature. +The function should return a consolidated `dict` with all routing information. + +~~~~exercism/note +The second `dict` can contain different/more properties than the ones shown in the example. +~~~~ + +```python +>>> extend_route_information({"from": "Berlin", "to": "Hamburg"}, {"length": "100", "speed": "50"}) +{"from": "Berlin", "to": "Hamburg", "length": "100", "speed": "50"} +``` + +## 5. Fix the wagon depot + +When Linus was surveying the wagon depot they noticed that the wagons were not getting stored in the correct order. +In addition to an ID, each wagon has a color that corresponds to the type of cargo it carries. +Wagons are stored in the depot in grids, where each column in the grid has wagons of the same color. + +However, the logistics system shows `lists` of wagons to be stored in the depot have their _rows_ grouped by color. +But for the storage grid to work correctly, each _row_ should have three different colors so that the _columns_ align by color. +Your friend would like you to sort out the wagon depot `lists`, so that the wagons get stored correctly. + +Implement a function called `fix_wagon_depot()` that accepts a `list` of three items. +Each `list` item is a sublist (or "row") that contains three `tuples`. +Each `tuple` is a `(<wagon ID>, <wagon color>)` pair. + +Your function should return a `list` with the three "row" `lists` reordered to have the wagons swapped into their correct positions. + +```python +>>> fix_wagon_depot([ + [(2, "red"), (4, "red"), (8, "red")], + [(5, "blue"), (9, "blue"), (13,"blue")], + [(3, "orange"), (7, "orange"), (11, "orange")], + ]) + +[ +[(2, "red"), (5, "blue"), (3, "orange")], +[(4, "red"), (9, "blue"), (7, "orange")], +[(8, "red"), (13,"blue"), (11, "orange")] +] +``` + +## Source + +### Created by + +- @meatball133 +- @BethanyG + +### Contributed to by + +- @IsaacG \ No newline at end of file diff --git a/python/locomotive-engineer/__pycache__/locomotive_engineer.cpython-313.pyc b/python/locomotive-engineer/__pycache__/locomotive_engineer.cpython-313.pyc new file mode 100644 index 0000000..4f1e5c9 Binary files /dev/null and b/python/locomotive-engineer/__pycache__/locomotive_engineer.cpython-313.pyc differ diff --git a/python/locomotive-engineer/__pycache__/locomotive_engineer.cpython-314.pyc b/python/locomotive-engineer/__pycache__/locomotive_engineer.cpython-314.pyc new file mode 100644 index 0000000..93c35dd Binary files /dev/null and b/python/locomotive-engineer/__pycache__/locomotive_engineer.cpython-314.pyc differ diff --git a/python/locomotive-engineer/__pycache__/locomotive_engineer_test.cpython-313-pytest-8.3.4.pyc b/python/locomotive-engineer/__pycache__/locomotive_engineer_test.cpython-313-pytest-8.3.4.pyc new file mode 100644 index 0000000..fe7352c Binary files /dev/null and b/python/locomotive-engineer/__pycache__/locomotive_engineer_test.cpython-313-pytest-8.3.4.pyc differ diff --git a/python/locomotive-engineer/__pycache__/locomotive_engineer_test.cpython-314-pytest-9.1.0.pyc b/python/locomotive-engineer/__pycache__/locomotive_engineer_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..7d05ebb Binary files /dev/null and b/python/locomotive-engineer/__pycache__/locomotive_engineer_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/locomotive-engineer/locomotive_engineer.py b/python/locomotive-engineer/locomotive_engineer.py new file mode 100644 index 0000000..8e09d21 --- /dev/null +++ b/python/locomotive-engineer/locomotive_engineer.py @@ -0,0 +1,63 @@ +"""Functions which helps the locomotive engineer to keep track of the train.""" + + +def get_list_of_wagons(*wagons_ids): + """Return a list of wagons. + + :param: arbitrary number of wagons. + :return: list - list of wagons. + """ + return list(wagons_ids) + + +def fix_list_of_wagons(each_wagons_id, missing_wagons): + """Fix the list of wagons. + + :param each_wagons_id: list - the list of wagons. + :param missing_wagons: list - the list of missing wagons. + :return: list - list of wagons. + """ + first, second, locomotive, *rest = each_wagons_id + (*fixed_list,) = locomotive, *missing_wagons, *rest, first, second + return fixed_list + + +def add_missing_stops(route: dict, **kwargs): + """Add missing stops to route dict. + + :param route: dict - the dict of routing information. + :param: arbitrary number of stops. + :return: dict - updated route dictionary. + """ + (*route["stops"],) = kwargs.values() + return route + + +def extend_route_information(route, more_route_information): + """Extend route information with more_route_information. + + :param route: dict - the route information. + :param more_route_information: dict - extra route information. + :return: dict - extended route information. + """ + return {**route, **more_route_information} + + +def fix_wagon_depot(wagons_rows): + """Fix the list of rows of wagons. + + :param wagons_rows: list[list[tuple]] - the list of rows of wagons. + :return: list[list[tuple]] - list of rows of wagons. + """ + # reordered_wagons: list[list[tuple]] = [] + # grid_1: list = [] + # grid_2: list = [] + # grid_3: list = [] + # for row in wagons_rows: + # wagon_1, wagon_2, wagon_3 = row + # grid_1.append(wagon_1) + # grid_2.append(wagon_2) + # grid_3.append(wagon_3) + # reordered_wagons = [grid_1, grid_2, grid_3] + # return reordered_wagons + return [[row_1, row_2, row_3] for (row_1, row_2, row_3) in zip(*wagons_rows)] diff --git a/python/locomotive-engineer/locomotive_engineer_test.py b/python/locomotive-engineer/locomotive_engineer_test.py new file mode 100644 index 0000000..95faf90 --- /dev/null +++ b/python/locomotive-engineer/locomotive_engineer_test.py @@ -0,0 +1,115 @@ +import unittest +import pytest +from locomotive_engineer import (get_list_of_wagons, + fix_list_of_wagons, + add_missing_stops, + extend_route_information, + fix_wagon_depot) + + +class LocomotiveEngineerTest(unittest.TestCase): + + @pytest.mark.task(taskno=1) + def test_get_list_of_wagons(self): + input_data = [(1,5,2,7,4), (1,5), (1,), (1,9,3), (1,10,6,3,9,8,4,14,24,7)] + output_data = [[1,5,2,7,4], [1,5], [1], [1,9,3], [1,10,6,3,9,8,4,14,24,7]] + + for variant, (input_data, expected) in enumerate(zip(input_data, output_data), start=1): + with self.subTest(f'variation #{variant}', input_data=input_data, expected=expected): + + actual_result = get_list_of_wagons(*input_data) + error_msg= (f'Called get_list_of_wagons{input_data}. ' + f'The function returned {actual_result}, but the ' + f'tests expected: {expected} as the wagon list instead.') + + self.assertEqual(actual_result, expected, msg=error_msg) + + @pytest.mark.task(taskno=2) + def test_fix_list_of_wagons(self): + input_data = [([2, 5, 1, 7, 4, 12, 6, 3, 13], [3, 17, 6, 15]), + ([3, 27, 1, 14, 10, 4, 12, 6, 23, 17, 13, 22, 28, 19], [8, 10, 5, 9, 36, 7, 20]), + ([4, 2, 1], [8, 6, 15]), + ([3, 14, 1, 25, 7, 19, 10], [8, 6, 4, 5, 9, 21, 2, 13]) + ] + output_data = [[1, 3, 17, 6, 15, 7, 4, 12, 6, 3, 13, 2, 5], + [1, 8, 10, 5, 9, 36, 7, 20, 14, 10, 4, 12, 6, 23, 17, 13, 22, 28, 19, 3, 27], + [1, 8, 6, 15, 4, 2], + [1, 8, 6, 4, 5, 9, 21, 2, 13, 25, 7, 19, 10, 3, 14] + ] + for variant, (input_data, expected) in enumerate(zip(input_data, output_data), start=1): + with self.subTest(f'variation #{variant}', input_data=input_data, expected=expected): + + actual_result = fix_list_of_wagons(input_data[0], input_data[1]) + error_msg= (f'Called fix_list_of_wagons({input_data[0]}, {input_data[1]}). ' + f'The function returned {actual_result}, but the ' + f'tests expected: {expected} as the wagon list instead.') + + self.assertEqual(actual_result, expected, msg=error_msg) + + @pytest.mark.task(taskno=3) + def test_add_missing_stops(self): + input_data = (({'from': 'Berlin', 'to': 'Hamburg'}, {'stop_1': 'Lepzig', 'stop_2': 'Hannover', 'stop_3': 'Frankfurt'}), + ({'from': 'Paris', 'to': 'London'}, {'stop_1': 'Lille'}), + ({'from': 'New York', 'to': 'Philadelphia'},{}), + ({'from': 'Gothenburg', 'to': 'Copenhagen'}, {'stop_1': 'Kungsbacka', 'stop_2': 'Varberg', 'stop_3': 'Halmstad', 'stop_4': 'Angelholm', 'stop_5': 'Lund', 'stop_6': 'Malmo'}) + ) + output_data = [{'from': 'Berlin', 'to': 'Hamburg', 'stops': ['Lepzig', 'Hannover', 'Frankfurt']}, + {'from': 'Paris', 'to': 'London', 'stops': ['Lille']}, + {'from': 'New York', 'to': 'Philadelphia', 'stops': []}, + {'from': 'Gothenburg', 'to': 'Copenhagen', 'stops': ['Kungsbacka', 'Varberg', 'Halmstad', 'Angelholm', 'Lund', 'Malmo']} + ] + for variant, (input_data, expected) in enumerate(zip(input_data, output_data), start=1): + with self.subTest(f'variation #{variant}', input_data=input_data, expected=expected): + + actual_result = add_missing_stops(input_data[0], **input_data[1]) + error_msg= (f'Called add_missing_stops({input_data[0]}, {input_data[1]}). ' + f'The function returned {actual_result}, but the ' + f'tests expected: {expected} as the set of stops.') + + self.assertEqual(actual_result, expected, msg=error_msg) + + @pytest.mark.task(taskno=4) + def test_extend_route_information(self): + input_data = [({'from': 'Berlin', 'to': 'Hamburg'}, {'timeOfArrival': '12:00', 'precipitation': '10', 'temperature': '5', 'caboose': 'yes'}), + ({'from': 'Paris', 'to': 'London'}, {'timeOfArrival': '10:30', 'temperature': '20', 'length': '15'}), + ({'from': 'Gothenburg', 'to': 'Copenhagen'}, {'precipitation': '1', 'timeOfArrival': '21:20', 'temperature': '-6'})] + output_data = [{'from': 'Berlin', 'to': 'Hamburg', 'timeOfArrival': '12:00', 'precipitation': '10', 'temperature': '5', 'caboose': 'yes'}, + {'from': 'Paris', 'to': 'London', 'timeOfArrival': '10:30', 'temperature': '20', 'length': '15'}, + {'from': 'Gothenburg', 'to': 'Copenhagen', 'precipitation': '1', 'timeOfArrival': '21:20', 'temperature': '-6'} + ] + + for variant, (input_data, expected) in enumerate(zip(input_data, output_data), start=1): + with self.subTest(f'variation #{variant}', input_data=input_data, expected=expected): + + actual_result = extend_route_information(input_data[0], input_data[1]) + error_msg= (f'Called extend_route_information({input_data[0]}, {input_data[1]}). ' + f'The function returned {actual_result}, but the ' + f'tests expected: {expected} as the route dictionary.') + + self.assertEqual(actual_result, expected, msg=error_msg) + + @pytest.mark.task(taskno=5) + def test_fix_wagon_depot(self): + input_data = ( + [[(2, 'red'), (4, 'red'), (8, 'red')], [(5, 'blue'), (9, 'blue'), (13, 'blue')], [(3, 'orange'), (7, 'orange'), (11, 'orange')]], + [[(6, 'blue'), (10, 'blue'), (14, 'blue')], [(7, 'red'), (4, 'red'), (2, 'red')], [(3, 'orange'), (11, 'orange'), (15, 'orange')]], + [[(7, 'pink'), (4, 'pink'), (2, 'pink')], [(10, 'green'), (6, 'green'), (14, 'green')], [(9, 'yellow'), (5, 'yellow'), (13, 'yellow')]], + [[(3, 'purple'), (11, 'purple'), (15, 'purple')], [(20, 'black'), (16, 'black'), (12, 'black')], [(19, 'white'), (17, 'white'), (18, 'white')]] + ) + + output_data = ( + [[(2, 'red'), (5, 'blue'), (3, 'orange')], [(4, 'red'), (9, 'blue'), (7, 'orange')], [(8, 'red'), (13, 'blue'), (11, 'orange')]], + [[(6, 'blue'), (7, 'red'), (3, 'orange')], [(10, 'blue'), (4, 'red'), (11, 'orange')], [(14, 'blue'), (2, 'red'), (15, 'orange')]], + [[(7, 'pink'), (10, 'green'), (9, 'yellow')], [(4, 'pink'), (6, 'green'), (5, 'yellow')], [(2, 'pink'), (14, 'green'), (13, 'yellow')]], + [[(3, 'purple'), (20, 'black'), (19, 'white')], [(11, 'purple'), (16, 'black'), (17, 'white')], [(15, 'purple'), (12, 'black'), (18, 'white')]] + ) + + for variant, (input_data, expected) in enumerate(zip(input_data, output_data), start=1): + with self.subTest(f'variation #{variant}', input_data=input_data, expected=expected): + + actual_result = fix_wagon_depot(input_data) + error_msg= (f'Called fix_wagon_depot({input_data}). ' + f'The function returned {actual_result}, but the ' + f'tests expected: {expected} as the wagon depot list.') + + self.assertEqual(actual_result, expected, msg=error_msg) diff --git a/python/making-the-grade/.exercism/config.json b/python/making-the-grade/.exercism/config.json new file mode 100644 index 0000000..d9edd46 --- /dev/null +++ b/python/making-the-grade/.exercism/config.json @@ -0,0 +1,22 @@ +{ + "authors": [ + "mohanrajanr", + "BethanyG" + ], + "contributors": [ + "pranasziaukas" + ], + "files": { + "solution": [ + "loops.py" + ], + "test": [ + "loops_test.py" + ], + "exemplar": [ + ".meta/exemplar.py" + ] + }, + "icon": "grep", + "blurb": "Learn about loops by grading and organizing your students exam scores." +} diff --git a/python/making-the-grade/.exercism/metadata.json b/python/making-the-grade/.exercism/metadata.json new file mode 100644 index 0000000..1f43bbc --- /dev/null +++ b/python/making-the-grade/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"making-the-grade","id":"ade6f1b3cf8e434fba3cb44e934d3d01","url":"https://exercism.org/tracks/python/exercises/making-the-grade","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/making-the-grade/HELP.md b/python/making-the-grade/HELP.md new file mode 100644 index 0000000..6ac515f --- /dev/null +++ b/python/making-the-grade/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +<br> + +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit loops.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/making-the-grade/HINTS.md b/python/making-the-grade/HINTS.md new file mode 100644 index 0000000..79e03af --- /dev/null +++ b/python/making-the-grade/HINTS.md @@ -0,0 +1,59 @@ +# Hints + +## General + +- [`while`][while-loops] loops are used for _indefinite_ (uncounted) iteration +- [`for`][for-loops] loops are used for _definite_, (counted) iteration. +- The keywords [`break` and `continue`][control flow] help customize loop behavior. +- [`range(<start>, stop, <step>)`][range] can be used to generate a sequence for a loop counter. +- The built-in [`enumerate()`][enumerate] will return (`<value>`, `<index>`) pairs to iterate over. + +Also being familiar with the following can help with completing the tasks: + +- [`lists`][list]: indexing, nested lists, [`<list>.append`][append and pop], [`<list>.pop()`][append and pop]. +- [`str`][str]: `str()` constructor, using the `+` to concatenate strings, optionally, [`f-strings`][f-strings]. + +## 1. Rounding Scores + +- `While` loops will continue to execute until their test condition evaluates to `False`. +- `<list>.pop()` will remove and return the last item in a `list`. +- Empty lists evaluate to `False` (most empty objects in Python are "Falsy") + +## 2. Non-Passing Students + +- There's no need to declare `loop` counters or `index` counters when iterating through an object using a `for` loop. +- A results counter does need to be set up and _incremented_ -- you'll want to `return` the count of non-passing students when the loop terminates. + +## 3. The "Best" + +- There's no need to declare `loop` counters or `index` counters when iterating through an object using a `for` loop. +- Having an empty `list` to add the "best" marks to is helpful here. +- `<list>.append()` can help add things to the results `list`. + +## 4. Calculating Letter Grades + +- These are _lower thresholds_. The _lower threshold_ for a "D" is a score of **41**, since an "F" is **<= 40**. +- [`range()`][range] can be helpful here to generate a sequence with the proper "F" -> "A" increments. +- [`round()`][round] without parameters should round off increments nicely. +- As with "the best" task, `<list>.append()` could be useful here to append items from `range()` into a results `list`. + +## 5. Matching Names to Scores + +- [`enumerate()`][enumerate] could be helpful here. +- If both lists are the same length and sorted the same way, could you use the `index` from one to retrieve a `value` from the other? + +## 6. A "Perfect" Score + +- There may be or may not be a student with a score of 100, and you can't return `[]` without checking **all** scores. +- The [`control flow`][control flow] statements `continue` and `break` may be useful here to move past unwanted values. + +[append and pop]: https://docs.python.org/3/tutorial/datastructures.html#more-on-lists +[control flow]: https://docs.python.org/3/tutorial/controlflow.html#break-and-continue-statements-and-else-clauses-on-loops +[enumerate]: https://docs.python.org/3/library/functions.html#enumerate +[f-strings]: https://docs.python.org/3/reference/lexical_analysis.html#formatted-string-literals +[for-loops]: https://docs.python.org/3/tutorial/controlflow.html#for-statements +[list]: https://docs.python.org/3/library/stdtypes.html#list +[range]: https://docs.python.org/3/tutorial/controlflow.html#the-range-function +[round]: https://docs.python.org/3/library/functions.html#round +[str]: https://docs.python.org/3/library/stdtypes.html#str +[while-loops]: https://docs.python.org/3/reference/compound_stmts.html#the-while-statement \ No newline at end of file diff --git a/python/making-the-grade/README.md b/python/making-the-grade/README.md new file mode 100644 index 0000000..fe60e12 --- /dev/null +++ b/python/making-the-grade/README.md @@ -0,0 +1,321 @@ +# Making the Grade + +Welcome to Making the Grade on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. +If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :) + +## Introduction + +Python has two looping constructs. +`while` loops for _indefinite_ (uncounted) iteration and `for` loops for _definite_, (counted) iteration. +The keywords `break`, `continue`, and `else` help customize loop behavior. +`range()` and `enumerate()` help with loop counting and indexing. + + +## While + +[`while`][while statement] loops will continue to execute as long as the `loop expression` or "test" evaluates to `True` in a [`boolean context`][truth value testing], terminating when it evaluates to `False`: + +```python + +# Lists are considered "truthy" in a boolean context if they +# contain one or more values, and "falsy" if they are empty. + +>>> placeholders = ["spam", "ham", "eggs", "green_spam", "green_ham", "green_eggs"] + +>>> while placeholders: +... print(placeholders.pop(0)) +... +'spam' +'ham' +'eggs' +'green_spam' +'green_ham' +'green_eggs' +``` + + +## For + +The basic [`for`][for statement] `loop` in Python is better described as a _`for each`_ which cycles through the values of any [iterable object][iterable], terminating when there are no values returned from calling [`next()`][next built-in]: + +```python + +>>> word_list = ["bird", "chicken", "barrel", "bongo"] + +>>> for word in word_list: +... if word.startswith("b"): +... print(f"{word.title()} starts with a B.") +... else: +... print(f"{word.title()} doesn't start with a B.") +... +'Bird starts with a B.' +'Chicken doesn\'t start with a B.' +'Barrel starts with a B.' +'Bongo starts with a B.' +``` + + +## Sequence Object range() + +When there isn't a specific `iterable` given, the special [`range()`][range] sequence is used as a loop counter. +`range()` requires an `int` before which to `stop` the sequence, and can optionally take `start` and `step` parameters. +If no `start` number is provided, the sequence will begin with 0. +`range()` objects are **lazy** (_values are generated on request_), support all [common sequence operations][common sequence operations], and take up a fixed amount of memory, no matter how long the sequence specified. + +```python +# Here we use range to produce some numbers, rather than creating a list of them in memory. +# The values will start with 1 and stop *before* 7 + +>>> for number in range(1, 7): +... if number % 2 == 0: +... print(f"{number} is even.") +... else: +... print(f"{number} is odd.") +'1 is odd.' +'2 is even.' +'3 is odd.' +'4 is even.' +'5 is odd.' +'6 is even.' + +# range() can also take a *step* parameter. +# Here we use range to produce only the "odd" numbers, starting with 3 and stopping *before* 15. + +>>> for number in range(3, 15, 2): +... if number % 2 == 0: +... print(f"{number} is even.") +... else: +... print(f"{number} is odd.") +... +'3 is odd.' +'5 is odd.' +'7 is odd.' +'9 is odd.' +'11 is odd.' +'13 is odd.' +``` + + +## Values and Indexes with enumerate() + +If both values and their indexes are needed, the built-in [`enumerate(<iterable>)`][enumerate] will return (`index`, `value`) pairs: + +```python + +>>> word_list = ["bird", "chicken", "barrel", "apple"] + +# *index* and *word* are the loop variables. +# Loop variables can be any valid python name. + +>>> for index, word in enumerate(word_list): +... if word.startswith("b"): +... print(f"{word.title()} (at index {index}) starts with a B.") +... else: +... print(f"{word.title()} (at index {index}) doesn't start with a B.") +... +'Bird (at index 0) starts with a B.' +'Chicken (at index 1) doesn\'t start with a B.' +'Barrel (at index 2) starts with a B.' +'Apple (at index 3) doesn\'t start with a B.' + + +# The same method can be used as a "lookup" for pairing items between two lists. +# Of course, if the lengths or indexes don't line up, this doesn't work. + +>>> word_list = ["cat", "chicken", "barrel", "apple", "spinach"] +>>> category_list = ["mammal", "bird", "thing", "fruit", "vegetable"] + +>>> for index, word in enumerate(word_list): +... print(f"{word.title()} is in category: {category_list[index]}.") +... +'Cat is in category: mammal.' +'Chicken is in category: bird.' +'Barrel is in category: thing.' +'Apple is in category: fruit.' +'Spinach is in category: vegetable.' +``` + + +## Altering Loop Behavior + +The [`continue`][continue statement] keyword can be used to skip forward to the next iteration cycle: + +```python +word_list = ["bird", "chicken", "barrel", "bongo", "sliver", "apple", "bear"] + +# This will skip *bird*, at index 0 +for index, word in enumerate(word_list): + if index == 0: + continue + if word.startswith("b"): + print(f"{word.title()} (at index {index}) starts with a b.") + +'Barrel (at index 2) starts with a b.' +'Bongo (at index 3) starts with a b.' +'Bear (at index 6) starts with a b.' +``` + + +The [`break`][break statement] (_like in many C-related languages_) keyword can be used to stop the iteration and "break out" of the innermost enclosing `loop`: + +```python +>>> word_list = ["bird", "chicken", "barrel", "bongo", "sliver", "apple"] + +>>> for index, word in enumerate(word_list): +... if word.startswith("b"): +... print(f"{word.title()} (at index {index}) starts with a B.") +... elif word == "sliver": +... break +... else: +... print(f"{word.title()} doesn't start with a B.") +... print("loop broken.") +... +'Bird (at index 0) starts with a B.' +'Chicken doesn\'t start with a B.' +'Barrel (at index 2) starts with a B.' +'Bongo (at index 3) starts with a B.' +'loop broken.' +``` + +[break statement]: https://docs.python.org/3/reference/simple_stmts.html#the-break-statement +[common sequence operations]: https://docs.python.org/3/library/stdtypes.html#common-sequence-operations +[continue statement]: https://docs.python.org/3/reference/simple_stmts.html#the-continue-statement +[enumerate]: https://docs.python.org/3/library/functions.html#enumerate +[for statement]: https://docs.python.org/3/reference/compound_stmts.html#for +[iterable]: https://docs.python.org/3/glossary.html#term-iterable +[next built-in]: https://docs.python.org/3/library/functions.html#next +[range]: https://docs.python.org/3/library/stdtypes.html#range +[truth value testing]: https://docs.python.org/3/library/stdtypes.html#truth-value-testing +[while statement]: https://docs.python.org/3/reference/compound_stmts.html#the-while-statement + +## Instructions + +You're a teaching assistant correcting student exams. +Keeping track of results manually is getting both tedious and mistake-prone. +You decide to make things a little more interesting by putting together some functions to count and calculate results for the class. + +## 1. Rounding Scores + +While you can give "partial credit" on exam questions, overall exam scores have to be `int`s. +So before you can do anything else with the class scores, you need to go through the grades and turn any `float` scores into `int`s. Lucky for you, Python has the built-in [`round()`][round] function you can use. + +Create the function `round_scores(student_scores)` that takes a `list` of `student_scores`. +This function should _consume_ the input `list` and `return` a new list with all the scores converted to `int`s. +The order of the scores in the resulting `list` is not important. + +```python +>>> student_scores = [90.33, 40.5, 55.44, 70.05, 30.55, 25.45, 80.45, 95.3, 38.7, 40.3] +>>> round_scores(student_scores) +... +[40, 39, 95, 80, 25, 31, 70, 55, 40, 90] +``` + +## 2. Non-Passing Students + +As you were grading the exam, you noticed some students weren't performing as well as you had hoped. +But you were distracted, and forgot to note exactly _how many_ students. + +Create the function `count_failed_students(student_scores)` that takes a `list` of `student_scores`. +This function should count up the number of students who don't have passing scores and return that count as an integer. +A student needs a score greater than **40** to achieve a passing grade on the exam. + +```python +>>> count_failed_students(student_scores=[90,40,55,70,30,25,80,95,38,40]) +5 +``` + +## 3. The "Best" + +The teacher you're assisting wants to find the group of students who've performed "the best" on this exam. +What qualifies as "the best" fluctuates, so you need to find the student scores that are **greater than or equal to** the current threshold. + +Create the function `above_threshold(student_scores, threshold)` taking `student_scores` (a `list` of grades), and `threshold` (the "top score" threshold) as parameters. +This function should return a `list` of all scores that are `>=` to `threshold`. + +```python +>>> above_threshold(student_scores=[90,40,55,70,30,68,70,75,83,96], threshold=75) +[90,75,83,96] +``` + +## 4. Calculating Letter Grades + +The teacher you are assisting likes to assign letter grades as well as numeric scores. +Since students rarely score 100 on an exam, the "letter grade" lower thresholds are calculated based on the highest score achieved, and increment evenly between the high score and the failing threshold of **<= 40**. + +Create the function `letter_grades(highest)` that takes the "highest" score on the exam as an argument, and returns a `list` of lower score thresholds for each "American style" grade interval: `["D", "C", "B", "A"]`. + + +```python +"""Where the highest score is 100, and failing is <= 40. + "F" <= 40 + 41 <= "D" <= 55 + 56 <= "C" <= 70 + 71 <= "B" <= 85 + 86 <= "A" <= 100 +""" + +>>> letter_grades(highest=100) +[41, 56, 71, 86] + + +"""Where the highest score is 88, and failing is <= 40. + "F" <= 40 + 41 <= "D" <= 52 + 53 <= "C" <= 64 + 65 <= "B" <= 76 + 77 <= "A" <= 88 +""" + +>>> letter_grades(highest=88) +[41, 53, 65, 77] +``` + +## 5. Matching Names to Scores + +You have a list of exam scores in descending order, and another list of student names also sorted in descending order by their exam scores. +You would like to match each student name with their exam score and print out an overall class ranking. + +Create the function `student_ranking(student_scores, student_names)` with parameters `student_scores` and `student_names`. +Match each student name on the student_names `list` with their score from the student_scores `list`. +You can assume each argument `list` will be sorted from highest score(er) to lowest score(er). +The function should return a `list` of strings with the format `<rank>. <student name>: <student score>`. + +```python +>>> student_scores = [100, 99, 90, 84, 66, 53, 47] +>>> student_names = ['Joci', 'Sara','Kora','Jan','John','Bern', 'Fred'] +>>> student_ranking(student_scores, student_names) +... +['1. Joci: 100', '2. Sara: 99', '3. Kora: 90', '4. Jan: 84', '5. John: 66', '6. Bern: 53', '7. Fred: 47'] +``` + +## 6. A "Perfect" Score + +Although a "perfect" score of 100 is rare on an exam, it is interesting to know if at least one student has achieved it. + +Create the function `perfect_score(student_info)` with parameter `student_info`. +`student_info` is a `list` of lists containing the name and score of each student: `[["Charles", 90], ["Tony", 80]]`. +The function should `return` _the first_ `[<name>, <score>]` pair of the student who scored 100 on the exam. + +If no 100 scores are found in `student_info`, an empty list `[]` should be returned. + +```python +>>> perfect_score(student_info=[["Charles", 90], ["Tony", 80], ["Alex", 100]]) +["Alex", 100] + +>>> perfect_score(student_info=[["Charles", 90], ["Tony", 80]]) +[] +``` + +[round]: https://docs.python.org/3/library/functions.html#round + +## Source + +### Created by + +- @mohanrajanr +- @BethanyG + +### Contributed to by + +- @pranasziaukas \ No newline at end of file diff --git a/python/making-the-grade/__pycache__/loops.cpython-313.pyc b/python/making-the-grade/__pycache__/loops.cpython-313.pyc new file mode 100644 index 0000000..c41babb Binary files /dev/null and b/python/making-the-grade/__pycache__/loops.cpython-313.pyc differ diff --git a/python/making-the-grade/__pycache__/loops.cpython-314.pyc b/python/making-the-grade/__pycache__/loops.cpython-314.pyc new file mode 100644 index 0000000..77fb1f1 Binary files /dev/null and b/python/making-the-grade/__pycache__/loops.cpython-314.pyc differ diff --git a/python/making-the-grade/__pycache__/loops_test.cpython-313-pytest-8.3.4.pyc b/python/making-the-grade/__pycache__/loops_test.cpython-313-pytest-8.3.4.pyc new file mode 100644 index 0000000..e6dea9b Binary files /dev/null and b/python/making-the-grade/__pycache__/loops_test.cpython-313-pytest-8.3.4.pyc differ diff --git a/python/making-the-grade/__pycache__/loops_test.cpython-314-pytest-9.1.0.pyc b/python/making-the-grade/__pycache__/loops_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..091ab07 Binary files /dev/null and b/python/making-the-grade/__pycache__/loops_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/making-the-grade/loops.py b/python/making-the-grade/loops.py new file mode 100644 index 0000000..65bc0f6 --- /dev/null +++ b/python/making-the-grade/loops.py @@ -0,0 +1,88 @@ +"""Functions for organizing and calculating student exam scores.""" + + +def round_scores(student_scores): + """Round all provided student scores. + + :param student_scores: list - float or int of student exam scores. + :return: list - student scores *rounded* to nearest integer value. + """ + rounded_scores: list = [] + for score in student_scores: + rounded_scores.append(round(score)) + return rounded_scores + + +def count_failed_students(student_scores): + """Count the number of failing students out of the group provided. + + :param student_scores: list - containing int student scores. + :return: int - count of student scores at or below 40. + """ + number_failed_students: int = 0 + for score in student_scores: + if score <= 40: + number_failed_students += 1 + return number_failed_students + + +def above_threshold(student_scores, threshold): + """Determine how many of the provided student scores were 'the best' based on the provided threshold. + + :param student_scores: list - of integer scores. + :param threshold: int - threshold to cross to be the "best" score. + :return: list - of integer scores that are at or above the "best" threshold. + """ + above_the_best: list = [] + for score in student_scores: + if score >= threshold: + above_the_best.append(score) + return above_the_best + + +def letter_grades(highest): + """Create a list of grade thresholds based on the provided highest grade. + + :param highest: int - value of highest exam score. + :return: list - of lower threshold scores for each D-A letter grade interval. + For example, where the highest score is 100, and failing is <= 40, + The result would be [41, 56, 71, 86]: + + 41 <= "D" <= 55 + 56 <= "C" <= 70 + 71 <= "B" <= 85 + 86 <= "A" <= 100 + """ + diff_between_levels: int = round((highest - 41) / 4) + scores_letter_grades: list = [] + for level in range(0, 4): + scores_letter_grades.append(41 + (level * diff_between_levels)) + return scores_letter_grades + + +def student_ranking(student_scores, student_names): + """Organize the student's rank, name, and grade information in descending order. + + :param student_scores: list - of scores in descending order. + :param student_names: list - of string names by exam score in descending order. + :return: list - of strings in format ["<rank>. <student name>: <score>"]. + """ + name_and_score: list = [ + f"{rank}. {name}: {score}" + for rank, (name, score) in enumerate( + zip(student_names, student_scores), start=1 + ) + ] + return name_and_score + + +def perfect_score(student_info): + """Create a list that contains the name and grade of the first student to make a perfect score on the exam. + + :param student_info: list - of [<student name>, <score>] lists. + :return: list - first `[<student name>, 100]` or `[]` if no student score of 100 is found. + """ + for name, score in student_info: + if score == 100: + return [name, score] + return [] diff --git a/python/making-the-grade/loops_test.py b/python/making-the-grade/loops_test.py new file mode 100644 index 0000000..f7ff977 --- /dev/null +++ b/python/making-the-grade/loops_test.py @@ -0,0 +1,226 @@ +import unittest +import pytest +from loops import ( + round_scores, + count_failed_students, + above_threshold, + letter_grades, + student_ranking, + perfect_score, +) + + +class MakingTheGradeTest(unittest.TestCase): + @pytest.mark.task(taskno=1) + def test_round_scores(self): + # Because we the input list can be mutated, the test data has been created + # as tuples, which we then convert to a list when the test runs. + # this makes accurate error messages easier to create. + test_data = [ + tuple(), + (0.5,), + (1.5,), + (90.33, 40.5, 55.44, 70.05, 30.55, 25.45, 80.45, 95.3, 38.7, 40.3), + (50, 36.03, 76.92, 40.7, 43, 78.29, 63.58, 91, 28.6, 88.0), + ] + result_data = [ + [], + [0], + [2], + [90, 40, 55, 70, 31, 25, 80, 95, 39, 40], + [50, 36, 77, 41, 43, 78, 64, 91, 29, 88], + ] + + for variant, (student_scores, expected) in enumerate( + zip(test_data, result_data), start=1 + ): + with self.subTest( + f"variation #{variant}", + student_scores=student_scores, + expected=expected, + ): + # Because the test_input is a tuple, it has to be converted to a list for the function call. + actual_result = round_scores(list(student_scores)) + error_message = ( + f"Called round_scores({list(student_scores)}). " + f"The function returned {sorted(actual_result)} after sorting, but " + f"the tests expected {sorted(expected)} after sorting. " + f"One or more scores were rounded incorrectly." + ) + + # everything is sorted for easier comparison. + self.assertEqual( + sorted(actual_result), sorted(expected), msg=error_message + ) + + @pytest.mark.task(taskno=2) + def test_count_failed_students(self): + test_data = [ + [89, 85, 42, 57, 90, 100, 95, 48, 70, 96], + [40, 40, 35, 70, 30, 41, 90], + ] + result_data = [0, 4] + + for variant, (student_scores, expected) in enumerate( + zip(test_data, result_data), start=1 + ): + with self.subTest( + f"variation #{variant}", + student_scores=student_scores, + expected=expected, + ): + actual_result = count_failed_students(student_scores) + error_message = ( + f"Called count_failed_students({student_scores}). " + f"The function returned {actual_result}, but " + f"the tests expected {expected} for the " + "number of students who failed." + ) + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=3) + def test_above_threshold(self): + test_data = [ + ([40, 39, 95, 80, 25, 31, 70, 55, 40, 90], 98), + ([88, 29, 91, 64, 78, 43, 41, 77, 36, 50], 80), + ([100, 89], 100), + ([88, 29, 91, 64, 78, 43, 41, 77, 36, 50], 78), + ([], 80), + ] + + result_data = [[], [88, 91], [100], [88, 91, 78], []] + + for variant, (params, expected) in enumerate( + zip(test_data, result_data), start=1 + ): + with self.subTest( + f"variation #{variant}", params=params, expected=expected + ): + actual_result = above_threshold(*params) + error_message = ( + f"Called above_threshold{params}. " + f"The function returned {actual_result}, but " + f"the tests expected {expected} for the " + "scores that are above the threshold." + ) + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=4) + def test_letter_grades(self): + test_data = [100, 97, 85, 92, 81] + + result_data = [ + [41, 56, 71, 86], + [41, 55, 69, 83], + [41, 52, 63, 74], + [41, 54, 67, 80], + [41, 51, 61, 71], + ] + + for variant, (highest, expected) in enumerate( + zip(test_data, result_data), start=1 + ): + with self.subTest( + f"variation #{variant}", highest=highest, expected=expected + ): + actual_result = letter_grades(highest) + error_message = ( + f"Called letter_grades({highest}). " + f"The function returned {actual_result}, but " + f"the tests expected {expected} for the " + "letter grade cutoffs." + ) + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=5) + def test_student_ranking(self): + test_data = [ + ([82], ["Betty"]), + ([88, 73], ["Paul", "Ernest"]), + ( + [100, 98, 92, 86, 70, 68, 67, 60], + ["Rui", "Betty", "Joci", "Yoshi", "Kora", "Bern", "Jan", "Rose"], + ), + ] + + result_data = [ + ["1. Betty: 82"], + ["1. Paul: 88", "2. Ernest: 73"], + [ + "1. Rui: 100", + "2. Betty: 98", + "3. Joci: 92", + "4. Yoshi: 86", + "5. Kora: 70", + "6. Bern: 68", + "7. Jan: 67", + "8. Rose: 60", + ], + ] + + for variant, (params, expected) in enumerate( + zip(test_data, result_data), start=1 + ): + with self.subTest( + f"variation #{variant}", params=params, expected=expected + ): + actual_result = student_ranking(*params) + error_message = ( + f"Called student_ranking{params}. " + f"The function returned {actual_result}, but " + f"the tests expected {expected} for the " + "student rankings." + ) + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=6) + def test_perfect_score(self): + test_data = [ + [["Joci", 100], ["Vlad", 100], ["Raiana", 100], ["Alessandro", 100]], + [["Jill", 30], ["Paul", 73]], + [], + [ + ["Rui", 60], + ["Joci", 58], + ["Sara", 91], + ["Kora", 93], + ["Alex", 42], + ["Jan", 81], + ["Lilliana", 40], + ["John", 60], + ["Bern", 28], + ["Vlad", 55], + ], + [ + ["Yoshi", 52], + ["Jan", 86], + ["Raiana", 100], + ["Betty", 60], + ["Joci", 100], + ["Kora", 81], + ["Bern", 41], + ["Rose", 94], + ], + ] + + result_data = [["Joci", 100], [], [], [], ["Raiana", 100]] + + for variant, (student_info, expected) in enumerate( + zip(test_data, result_data), start=1 + ): + with self.subTest( + f"variation #{variant}", student_info=student_info, expected=expected + ): + actual_result = perfect_score(student_info) + error_message = ( + f"Called perfect_score({student_info}). " + f"The function returned {actual_result}, but " + f"the tests expected {expected} for the " + 'first "perfect" score.' + ) + + self.assertEqual(actual_result, expected, msg=error_message) diff --git a/python/matching-brackets/.exercism/config.json b/python/matching-brackets/.exercism/config.json new file mode 100644 index 0000000..b07c1ab --- /dev/null +++ b/python/matching-brackets/.exercism/config.json @@ -0,0 +1,32 @@ +{ + "authors": [ + "behrtam" + ], + "contributors": [ + "atg-abhishek", + "BethanyG", + "cmccandless", + "Dog", + "ikhadykin", + "kylecjo", + "N-Parsons", + "Nishant23", + "pheanex", + "thomasjpfan", + "tqa236", + "yawpitch" + ], + "files": { + "solution": [ + "matching_brackets.py" + ], + "test": [ + "matching_brackets_test.py" + ], + "example": [ + ".meta/example.py" + ] + }, + "blurb": "Make sure the brackets and braces all match.", + "source": "Ginna Baker" +} diff --git a/python/matching-brackets/.exercism/metadata.json b/python/matching-brackets/.exercism/metadata.json new file mode 100644 index 0000000..c7e50f3 --- /dev/null +++ b/python/matching-brackets/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"matching-brackets","id":"bbb80640400146e48aa23f01af95f42a","url":"https://exercism.org/tracks/python/exercises/matching-brackets","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/matching-brackets/HELP.md b/python/matching-brackets/HELP.md new file mode 100644 index 0000000..35275ae --- /dev/null +++ b/python/matching-brackets/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +<br> + +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit matching_brackets.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/matching-brackets/README.md b/python/matching-brackets/README.md new file mode 100644 index 0000000..92246ad --- /dev/null +++ b/python/matching-brackets/README.md @@ -0,0 +1,44 @@ +# Matching Brackets + +Welcome to Matching Brackets on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Introduction + +You're given the opportunity to write software for the Bracketeer™, an ancient but powerful mainframe. +The software that runs on it is written in a proprietary language. +Much of its syntax is familiar, but you notice _lots_ of brackets, braces and parentheses. +Despite the Bracketeer™ being powerful, it lacks flexibility. +If the source code has any unbalanced brackets, braces or parentheses, the Bracketeer™ crashes and must be rebooted. +To avoid such a scenario, you start writing code that can verify that brackets, braces, and parentheses are balanced before attempting to run it on the Bracketeer™. + +## Instructions + +Given a string containing brackets `[]`, braces `{}`, parentheses `()`, or any combination thereof, verify that any and all pairs are matched and nested correctly. +Any other characters should be ignored. +For example, `"{what is (42)}?"` is balanced and `"[text}"` is not. + +## Source + +### Created by + +- @behrtam + +### Contributed to by + +- @atg-abhishek +- @BethanyG +- @cmccandless +- @Dog +- @ikhadykin +- @kylecjo +- @N-Parsons +- @Nishant23 +- @pheanex +- @thomasjpfan +- @tqa236 +- @yawpitch + +### Based on + +Ginna Baker \ No newline at end of file diff --git a/python/matching-brackets/__pycache__/matching_brackets.cpython-313.pyc b/python/matching-brackets/__pycache__/matching_brackets.cpython-313.pyc new file mode 100644 index 0000000..f770dc8 Binary files /dev/null and b/python/matching-brackets/__pycache__/matching_brackets.cpython-313.pyc differ diff --git a/python/matching-brackets/__pycache__/matching_brackets.cpython-314.pyc b/python/matching-brackets/__pycache__/matching_brackets.cpython-314.pyc new file mode 100644 index 0000000..b889741 Binary files /dev/null and b/python/matching-brackets/__pycache__/matching_brackets.cpython-314.pyc differ diff --git a/python/matching-brackets/__pycache__/matching_brackets_test.cpython-313-pytest-8.3.5.pyc b/python/matching-brackets/__pycache__/matching_brackets_test.cpython-313-pytest-8.3.5.pyc new file mode 100644 index 0000000..71fc268 Binary files /dev/null and b/python/matching-brackets/__pycache__/matching_brackets_test.cpython-313-pytest-8.3.5.pyc differ diff --git a/python/matching-brackets/__pycache__/matching_brackets_test.cpython-314-pytest-9.1.0.pyc b/python/matching-brackets/__pycache__/matching_brackets_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..66a230c Binary files /dev/null and b/python/matching-brackets/__pycache__/matching_brackets_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/matching-brackets/matching_brackets.py b/python/matching-brackets/matching_brackets.py new file mode 100644 index 0000000..172b1b4 --- /dev/null +++ b/python/matching-brackets/matching_brackets.py @@ -0,0 +1,28 @@ +def is_paired(input_string: str) -> bool: + brackets_list: list = [] + for char in input_string: + match char: + case "(" | "{" | "[": + brackets_list.append(char) + case ")": + if len(brackets_list) == 0: + return False + elif brackets_list[-1] != "(": + return False + else: + brackets_list.pop() + case "]": + if len(brackets_list) == 0: + return False + elif brackets_list[-1] != "[": + return False + else: + brackets_list.pop() + case "}": + if len(brackets_list) == 0: + return False + elif brackets_list[-1] != "{": + return False + else: + brackets_list.pop() + return True if len(brackets_list) == 0 else False diff --git a/python/matching-brackets/matching_brackets_test.py b/python/matching-brackets/matching_brackets_test.py new file mode 100644 index 0000000..a8321d9 --- /dev/null +++ b/python/matching-brackets/matching_brackets_test.py @@ -0,0 +1,76 @@ +# These tests are auto-generated with test data from: +# https://github.com/exercism/problem-specifications/tree/main/exercises/matching-brackets/canonical-data.json +# File last updated on 2023-07-19 + +import unittest + +from matching_brackets import ( + is_paired, +) + + +class MatchingBracketsTest(unittest.TestCase): + def test_paired_square_brackets(self): + self.assertEqual(is_paired("[]"), True) + + def test_empty_string(self): + self.assertEqual(is_paired(""), True) + + def test_unpaired_brackets(self): + self.assertEqual(is_paired("[["), False) + + def test_wrong_ordered_brackets(self): + self.assertEqual(is_paired("}{"), False) + + def test_wrong_closing_bracket(self): + self.assertEqual(is_paired("{]"), False) + + def test_paired_with_whitespace(self): + self.assertEqual(is_paired("{ }"), True) + + def test_partially_paired_brackets(self): + self.assertEqual(is_paired("{[])"), False) + + def test_simple_nested_brackets(self): + self.assertEqual(is_paired("{[]}"), True) + + def test_several_paired_brackets(self): + self.assertEqual(is_paired("{}[]"), True) + + def test_paired_and_nested_brackets(self): + self.assertEqual(is_paired("([{}({}[])])"), True) + + def test_unopened_closing_brackets(self): + self.assertEqual(is_paired("{[)][]}"), False) + + def test_unpaired_and_nested_brackets(self): + self.assertEqual(is_paired("([{])"), False) + + def test_paired_and_wrong_nested_brackets(self): + self.assertEqual(is_paired("[({]})"), False) + + def test_paired_and_wrong_nested_brackets_but_innermost_are_correct(self): + self.assertEqual(is_paired("[({}])"), False) + + def test_paired_and_incomplete_brackets(self): + self.assertEqual(is_paired("{}["), False) + + def test_too_many_closing_brackets(self): + self.assertEqual(is_paired("[]]"), False) + + def test_early_unexpected_brackets(self): + self.assertEqual(is_paired(")()"), False) + + def test_early_mismatched_brackets(self): + self.assertEqual(is_paired("{)()"), False) + + def test_math_expression(self): + self.assertEqual(is_paired("(((185 + 223.85) * 15) - 543)/2"), True) + + def test_complex_latex_expression(self): + self.assertEqual( + is_paired( + "\\left(\\begin{array}{cc} \\frac{1}{3} & x\\\\ \\mathrm{e}^{x} &... x^2 \\end{array}\\right)" + ), + True, + ) diff --git a/python/mecha-munch-management/.exercism/config.json b/python/mecha-munch-management/.exercism/config.json new file mode 100644 index 0000000..b75803a --- /dev/null +++ b/python/mecha-munch-management/.exercism/config.json @@ -0,0 +1,24 @@ +{ + "authors": [ + "meatball133", + "BethanyG" + ], + "contributors": [ + ], + "files": { + "solution": [ + "dict_methods.py" + ], + "test": [ + "dict_methods_test.py" + ], + "exemplar": [ + ".meta/exemplar.py" + ], + "editor": [ + "dict_methods_test_data.py" + ] + }, + "icon": "gross-store", + "blurb": "Learn about dictionary methods by building a shopping cart MVP for the Mecha Munch grocery app." +} diff --git a/python/mecha-munch-management/.exercism/metadata.json b/python/mecha-munch-management/.exercism/metadata.json new file mode 100644 index 0000000..fcc81ac --- /dev/null +++ b/python/mecha-munch-management/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"mecha-munch-management","id":"06c21c3131224c7d9bcc64e988c58106","url":"https://exercism.org/tracks/python/exercises/mecha-munch-management","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/mecha-munch-management/HELP.md b/python/mecha-munch-management/HELP.md new file mode 100644 index 0000000..18274f5 --- /dev/null +++ b/python/mecha-munch-management/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +<br> + +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit dict_methods.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/mecha-munch-management/HINTS.md b/python/mecha-munch-management/HINTS.md new file mode 100644 index 0000000..cc44bf0 --- /dev/null +++ b/python/mecha-munch-management/HINTS.md @@ -0,0 +1,57 @@ +# Hints + +## General + +Remember, this is an [MVP][mvp]. +That means you don't need to get too fancy with error handling or different "edge case" scenarios. +It's OK to be simple and direct with the functions you are writing. + +The dictionary section of the [official tutorial][dicts-docs] and the mapping type [official library reference][mapping-types-dict] are excellent places to look for more help with all these methods. + + +## 1. Add Item(s) to the Users Shopping Cart + +- You will need to iterate through each item in `items_to_add`. +- You can avoid a `KeyError` when a key is missing by using a `dict` [method][set-default] that takes a _default value_ as one of its arguments. +- It is also possible to accomplish the same thing manually in the `loop` by using some checking and error handling, but the `dict` method is easier. + +## 2. Read in Items Listed in the Users Notes App + +- Remember, Python's got a method for _everything_. This one is a _classmethod_ that's an easy way to [populate a `dict`][fromkeys] with keys. +- This `dict` method returns a _new dictionary_, populated with default values. If no value is given, the default value will become `None` + +## 3. Update Recipe "Ideas" Section + +- Don't overthink this one! This can be solved in **one** `dict` method call. +- The key word here is .... [_update_][update]. + +## 4. Sort the Items in the User Cart + +- What method would you call to get an [iterable view of items][items] in the dictionary? +- If you had a `list` or a `tuple`, what [`built-in`][builtins] function might you use to sort them? +- The built-in function you want is the one that returns a _copy_, and doesn't mutate the original. + +## 5. Send User Shopping Cart to Store for Fulfillment + +- Having a fresh, empty dictionary here as the `fulfillment_cart` might be handy for adding in items. +- `Looping` through the members of the cart might be the most direct way of accessing things here. +- What method would you call to get an [iterable view of just the keys][keys] of the dictionary? +- Remember that you can get the `value` of a given key by using `<dict name>[<key_name>]` syntax. +- If you had a `list` or a `tuple`, what [`built-in`][builtins] function might you use to sort them? +- Remember that the `built-in` function can take an optional `reverse=True` argument. + +## 6. Update the Store Inventory to Reflect what a User Has Ordered. + +- There is a method that will give you an iterable view of (`key`, `value`) pairs from the dictionary. +- You can access an item in a _nested tuple_ using _bracket notation_: `<tuple>[<nested_tuple>][<index_of_value>]` +- Don't forget to check if an inventory count falls to zero, you'll need to add in the "Out of Stock" message. + +[builtins]: https://docs.python.org/3/library/functions.html +[dicts-docs]: https://docs.python.org/3/tutorial/datastructures.html#dictionaries +[fromkeys]: https://docs.python.org/3/library/stdtypes.html#dict.fromkeys +[items]: https://docs.python.org/3/library/stdtypes.html#dict.items +[keys]: https://docs.python.org/3/library/stdtypes.html#dict.keys +[mapping-types-dict]: https://docs.python.org/3/library/stdtypes.html#mapping-types-dict +[mvp]: https://en.wikipedia.org/wiki/Minimum_viable_product +[set-default]: https://docs.python.org/3/library/stdtypes.html#dict.setdefault +[update]: https://docs.python.org/3/library/stdtypes.html#dict.update \ No newline at end of file diff --git a/python/mecha-munch-management/README.md b/python/mecha-munch-management/README.md new file mode 100644 index 0000000..24dd3a4 --- /dev/null +++ b/python/mecha-munch-management/README.md @@ -0,0 +1,364 @@ +# Mecha Munch Management + +Welcome to Mecha Munch Management on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. +If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :) + +## Introduction + +The `dict` class in Python provides many useful [methods][dict-methods] for working with dictionaries. +Some were introduced in the concept for `dicts`. +Here we cover a few more - along with some techniques for iterating through and manipulating dictionaries. + +### Use `setdefault()` for Error-Free Insertion + +The dictionary concept previously covered that `.get(key, <default value>)` returns an existing `value` or the `default value` if a `key` is not found in a dictionary, thereby avoiding a `KeyError`. +This works well in situations where you would rather not have extra error handling but cannot trust that a looked-for `key` will be present. + +For a similarly "safe" (_without KeyError_) insertion operation, there is the `.setdefault(key, <default value>)` method. +`setdefault(key, <default value>)` will return the `value` if the `key` is found in the dictionary. +If the key is **not** found, it will _insert_ the (`key`, `default value`) pair and return the `default value` for use. + +```python +>>> palette_I = {'Grassy Green': '#9bc400', 'Purple Mountains Majesty': '#8076a3', 'Misty Mountain Pink': '#f9c5bd'} + +# Looking for the value associated with key "Rock Brown". +# The key does not exist, so it is added with the default value, and the value is returned. +>>> palette_I.setdefault('Rock Brown', '#694605') +'#694605' + +# The (key, default value) pair has now been added to the dictionary. +>>> palette_I +{'Grassy Green': '#9bc400', 'Purple Mountains Majesty': '#8076a3', 'Misty Mountain Pink': '#f9c5bd', 'Rock Brown': '#694605'} +``` + +## Use `fromkeys()` to Populate a Dictionary from an Iterable + +To quickly populate a dictionary with various `keys` and default values, the _class method_ [`fromkeys(iterable, <default value>)`][fromkeys] will iterate through an iterable of `keys` and create a new `dict`. +All `values` will be set to the `default value` provided: + +```python +>>> new_dict = dict.fromkeys(['Grassy Green', 'Purple Mountains Majesty', 'Misty Mountain Pink'], 'fill in hex color here') + +{'Grassy Green': 'fill in hex color here', + 'Purple Mountains Majesty': 'fill in hex color here', + 'Misty Mountain Pink': 'fill in hex color here'} +``` + +## Iterating Over Entries in a Dictionary Via Views + +The `.keys()`, `.values()`, and `.items()` methods return [_iterable views_][dict-views] of a dictionary. + +These views can be used to easily loop over entries without altering them. +Views are also _dynamic_ -- when underlying dictionary data changes, the associated `view object` will reflect the change: + +```python +>>> palette_I = {'Grassy Green': '#9bc400', + 'Purple Mountains Majesty': '#8076a3', + 'Misty Mountain Pink': '#f9c5bd'} + +# Using .keys() returns a list of keys. +>>> palette_I.keys() +dict_keys(['Grassy Green', 'Purple Mountains Majesty', 'Misty Mountain Pink']) + +# Using .values() returns a list of values. +>>> palette_I.values() +dict_values(['#9bc400', '#8076a3', '#f9c5bd']) + +# Using .items() returns a list of (key, value) tuples. +>>> palette_I.items() +dict_items([('Grassy Green', '#9bc400'), ('Purple Mountains Majesty', '#8076a3'), ('Misty Mountain Pink', '#f9c5bd')]) + +# Views are dynamic. Changing values in the dict changes all of the associated views. +>>> palette_I['Purple Mountains Majesty'] = (128, 118, 163) +>>> palette_I['Deep Red'] = '#932432' + +>>> palette_I.values() +dict_values(['#9bc400', (128, 118, 163), '#f9c5bd', '#932432']) + +>>> palette_I.keys() +dict_keys(['Grassy Green', 'Purple Mountains Majesty', 'Misty Mountain Pink', 'Deep Red']) + +>>> palette_I.items() +dict_items([('Grassy Green', '#9bc400'), ('Purple Mountains Majesty', (128, 118, 163)), ('Misty Mountain Pink', '#f9c5bd'), ('Deep Red', '#932432')]) +``` + +## More on `.keys()`, `.values()`, and `.items()` + +In Python 3.7+, `dicts` preserve the order in which entries are inserted allowing First-in, First-out (_`FIFO`_), iteration when using `.keys()`, `.values()`, or `.items()`. + +In Python 3.8+, views are also _reversible_. +This allows keys, values, or (`key`, `value`) pairs to be iterated over in Last-in, First-out (`LIFO`) order by using `reversed(<dict>.keys())`, `reversed(<dict>.values())`, or `reversed(<dict>.items())`: + +```python +>>> palette_II = {'Factory Stone Purple': '#7c677f', 'Green Treeline': '#478559', 'Purple baseline': '#161748'} + +# Iterating in insertion order +>>> for item in palette_II.items(): +... print(item) +... +('Factory Stone Purple', '#7c677f') +('Green Treeline', '#478559') +('Purple baseline', '#161748') + + +# Iterating in the reverse direction. +>>> for item in reversed(palette_II.items()): +... print (item) +... +('Purple baseline', '#161748') +('Green Treeline', '#478559') +('Factory Stone Purple', '#7c677f') +``` + +## Sorting a Dictionary + +Dictionaries do not have a built-in sorting method. +However, it is possible to sort a `dict` _view_ using the built-in function `sorted()` with `.items()`. +The sorted view can then be used to create a new dictionary. +Like iteration, the default sort is over dictionary `keys`. + +```python +# Default ordering for a dictionary is last in, first out (LIFO). +>>> color_palette = {'Grassy Green': '#9bc400', + 'Purple Mountains Majesty': '#8076a3', + 'Misty Mountain Pink': '#f9c5bd', + 'Factory Stone Purple': '#7c677f', + 'Green Treeline': '#478559', + 'Purple baseline': '#161748'} + + +# The default sort order for a dictionary uses the keys. +>>> sorted_palette = dict(sorted(color_palette.items())) +>>> sorted_palette +{'Factory Stone Purple': '#7c677f', + 'Grassy Green': '#9bc400', + 'Green Treeline': '#478559', + 'Misty Mountain Pink': '#f9c5bd', + 'Purple Mountains Majesty': '#8076a3', + 'Purple baseline': '#161748'} +``` + +## Combining Dictionaries with `.update()` + +`<dict_one>.update(<dict_two>)` can be used to _combine_ two dictionaries. +This method will take the (`key`,`value`) pairs of `<dict_two>` and write them into `<dict_one>`: + +```python +>>> palette_I = {'Grassy Green': '#9bc400', + 'Purple Mountains Majesty': '#8076a3', + 'Misty Mountain Pink': '#f9c5bd'} +>>> palette_II = {'Factory Stone Purple': '#7c677f', + 'Green Treeline': '#478559', + 'Purple Baseline': '#161748'} + +>>> palette_I.update(palette_II) + +# Note that new items from palette_II are added. +>>> palette_I +{'Grassy Green': '#9bc400', 'Purple Mountains Majesty': '#8076a3', 'Misty Mountain Pink': '#f9c5bd', 'Factory Stone Purple': '#7c677f', 'Green Treeline': '#478559', 'Purple Baseline': '#161748'} +``` + +Where keys in the two dictionaries _overlap_, the `value` in `dict_one` will be _overwritten_ by the corresponding `value` from `dict_two`: + +```python +>>> palette_I = {'Grassy Green': '#9bc400', 'Purple Mountains Majesty': '#8076a3', 'Misty Mountain Pink': '#f9c5bd', + 'Factory Stone Purple': '#7c677f', 'Green Treeline': '#478559', 'Purple baseline': '#161748'} +>>> palette_III = {'Grassy Green': (155, 196, 0), 'Purple Mountains Majesty': (128, 118, 163), + 'Misty Mountain Pink': (249, 197, 189)} +>>> palette_I.update(palette_III) + +# Overlapping values in palette_I are replaced with values from palette_III +>>> palette_I +{'Grassy Green': (155, 196, 0), + 'Purple Mountains Majesty': (128, 118, 163), + 'Misty Mountain Pink': (249, 197, 189), + 'Factory Stone Purple': '#7c677f', + 'Green Treeline': '#478559', 'Purple baseline': '#161748'} +``` + +## Merge or Update Dictionaries Via the Union (`|`) Operators + +Python 3.9 introduces a different means of merging `dicts`: the `union` operators. +`dict_one | dict_two` will create a **new dictionary**, made up of the (`key`, `value`) pairs of `dict_one` and `dict_two`. +When both dictionaries share keys, `dict_two` values take precedence. + +```python +>>> palette_I = {'Grassy Green': '#9bc400', 'Purple Mountains Majesty': '#8076a3', 'Misty Mountain Pink': '#f9c5bd'} +>>> palette_II = {'Factory Stone Purple': '#7c677f', 'Green Treeline': '#478559', 'Purple baseline': '#161748'} +>>> new_dict = palette_I | palette_II +>>> new_dict +... +{'Grassy Green': '#9bc400', + 'Purple Mountains Majesty': '#8076a3', + 'Misty Mountain Pink': '#f9c5bd', + 'Factory Stone Purple': '#7c677f', + 'Green Treeline': '#478559', + 'Purple baseline': '#161748'} +``` + +`dict_one |= other` behaves similar to `<dict_one>.update(<other>)`, but in this case, `other` can be either a `dict` or an iterable of (`key`, `value`) pairs: + +```python +>>> palette_III = {'Grassy Green': (155, 196, 0), + 'Purple Mountains Majesty': (128, 118, 163), + 'Misty Mountain Pink': (249, 197, 189)} +>>> new_dict |= palette_III +>>> new_dict +... +{'Grassy Green': (155, 196, 0), +'Purple Mountains Majesty': (128, 118, 163), +'Misty Mountain Pink': (249, 197, 189), +'Factory Stone Purple': '#7c677f', +'Green Treeline': '#478559', +'Purple baseline': '#161748'} +``` + +For a detailed explanation of dictionaries and methods for working with them, the [official tutorial][dicts-docs] and the [official library reference][mapping-types-dict] are excellent starting places. + +[Real Python][how-to-dicts] and [Finxter][fi-dict-guide] also have very thorough articles on Python dictionaries. + +[dict-methods]: https://docs.python.org/3/library/stdtypes.html#dict +[dict-views]: https://docs.python.org/3/library/stdtypes.html#dict-views +[dicts-docs]: https://docs.python.org/3/tutorial/datastructures.html#dictionaries +[fi-dict-guide]: https://blog.finxter.com/python-dictionary +[fromkeys]: https://docs.python.org/3/library/stdtypes.html#dict.fromkeys +[how-to-dicts]: https://realpython.com/python-dicts/ +[mapping-types-dict]: https://docs.python.org/3/library/stdtypes.html#mapping-types-dict + +## Instructions + +Mecha Munch™, a grocery shopping automation company has just hired you to work on their ordering app. +Your team is tasked with building an MVP (_[minimum viable product][mvp]_) that manages all the basic shopping cart activities, allowing users to add, remove, and sort their grocery orders. +Thankfully, a different team is handling all the money and check-out functions! + +## 1. Add Item(s) to the Users Shopping Cart + +The MVP should allow the user to add items to their shopping cart. +This could be a single item or multiple items at once. +Since this is an MVP, item quantity is indicated by _repeats_. +If a user wants to add 2 Oranges, 'Oranges' will appear twice in the input iterable. +If the user already has the item in their cart, the cart quantity should be increased by 1. +If the item is _new_ to the cart, it should be added with a quantity of 1. + +Create the function `add_item(<current_cart>, <items_to_add>)` that takes a cart dictionary and any list-like iterable of items to add as arguments. +It should return a new/updated shopping cart dictionary for the user. + +```python +>>> add_item({'Banana': 3, 'Apple': 2, 'Orange': 1}, + ('Apple', 'Apple', 'Orange', 'Apple', 'Banana')) +{'Banana': 4, 'Apple': 5, 'Orange': 2} + +>>> add_item({'Banana': 3, 'Apple': 2, 'Orange': 1}, + ['Banana', 'Orange', 'Blueberries', 'Banana']) +{'Banana': 5, 'Apple': 2, 'Orange': 2, 'Blueberries': 1} +``` + +## 2. Read in Items Listed in the Users Notes App + +Uh-oh. +Looks like the product team is engaging in [feature creep][feature creep]. +They want to add extra functionality to the MVP. +The application now has to create a shopping cart by reading items off a users notes app. +Convenient for the users, but slightly more work for the team. + +Create the function `read_notes(<notes>)` that can take any list-like iterable as an argument. +The function should parse the items and create a user shopping cart/dictionary. +Each item should be added with a quantity of 1. +The new user cart should then be returned. + +```python +>>> read_notes(('Banana','Apple', 'Orange')) +{'Banana': 1, 'Apple': 1, 'Orange': 1} + +>>> read_notes(['Blueberries', 'Pear', 'Orange', 'Banana', 'Apple']) +{'Blueberries' : 1, 'Pear' : 1, 'Orange' : 1, 'Banana' : 1, 'Apple' : 1} +``` + +## 3. Update Recipe "Ideas" Section + +The app has an "ideas" section that's filled with finished recipes from various cuisines. +The user can select any one of these recipes and have all its ingredients added to their shopping cart automatically. +The project manager has asked you create a way to edit these "ideas" recipes, since the content team keeps changing around ingredients and quantities. + +Create the function `update_recipes(<ideas>, <recipe_updates>)` that takes an "ideas" dictionary and an iterable of recipe updates as arguments. +The function should return the new/updated "ideas" dictionary. + +```python +>>> update_recipes({'Banana Bread' : {'Banana': 1, 'Apple': 1, 'Walnuts': 1, 'Flour': 1, 'Eggs': 2, 'Butter': 1}, + 'Raspberry Pie' : {'Raspberry': 1, 'Orange': 1, 'Pie Crust': 1, 'Cream Custard': 1}}, +(('Banana Bread', {'Banana': 4, 'Walnuts': 2, 'Flour': 1, 'Butter': 1, 'Milk': 2, 'Eggs': 3}),)) +... + +{'Banana Bread' : {'Banana': 4, 'Walnuts': 2, 'Flour': 1, 'Butter': 1, 'Milk': 2, 'Eggs': 3}, + 'Raspberry Pie' : {'Raspberry': 1, 'Orange': 1, 'Pie Crust': 1, 'Cream Custard': 1}} + +>>> update_recipes({'Banana Bread' : {'Banana': 1, 'Apple': 1, 'Walnuts': 1, 'Flour': 1, 'Eggs': 2, 'Butter': 1}, + 'Raspberry Pie' : {'Raspberry': 1, 'Orange': 1, 'Pie Crust': 1, 'Cream Custard': 1}, + 'Pasta Primavera': {'Eggs': 1, 'Carrots': 1, 'Spinach': 2, 'Tomatoes': 3, 'Parmesan': 2, 'Milk': 1, 'Onion': 1}}, +[('Raspberry Pie', {'Raspberry': 3, 'Orange': 1, 'Pie Crust': 1, 'Cream Custard': 1, 'Whipped Cream': 2}), +('Pasta Primavera', {'Eggs': 1, 'Mixed Veggies': 2, 'Parmesan': 2, 'Milk': 1, 'Spinach': 1, 'Bread Crumbs': 1}), +('Blueberry Crumble', {'Blueberries': 2, 'Whipped Creme': 2, 'Granola Topping': 2, 'Yogurt': 3})]) +... + +{'Banana Bread': {'Banana': 1, 'Apple': 1, 'Walnuts': 1, 'Flour': 1, 'Eggs': 2, 'Butter': 1}, + 'Raspberry Pie': {'Raspberry': 3, 'Orange': 1, 'Pie Crust': 1, 'Cream Custard': 1, 'Whipped Cream': 2}, + 'Pasta Primavera': {'Eggs': 1, 'Mixed Veggies': 2, 'Parmesan': 2, 'Milk': 1, 'Spinach': 1, 'Bread Crumbs': 1}, + 'Blueberry Crumble': {'Blueberries': 2, 'Whipped Creme': 2, 'Granola Topping': 2, 'Yogurt': 3}} +``` + +## 4. Sort the Items in the User Cart + +Once a user has started a cart, the app allows them to sort their items alphabetically. +This makes things easier to find, and helps when there are data-entry errors like having 'potatoes' and 'Potato' in the database. + +Create the function `sort_entries(<cart>)` that takes a shopping cart/dictionary as an argument and returns a new, alphabetically sorted one. + +```python +>>> sort_entries({'Banana': 3, 'Apple': 2, 'Orange': 1}) +{'Apple': 2, 'Banana':3, 'Orange': 1} +``` + +## 5. Send User Shopping Cart to Store for Fulfillment + +The app needs to send a given users cart to the store for fulfillment. +However, the shoppers in the store need to know which store aisle the item can be found in and if the item needs refrigeration. +So (_rather arbitrarily_) the "fulfillment cart" needs to be sorted in reverse alphabetical order with item quantities combined with location and refrigeration information. + +Create the function `send_to_store(<cart>, <aisle_mapping>)` that takes a user shopping cart and a dictionary that has store aisle number and a `True`/`False` for refrigeration needed for each item. +The function should `return` a combined "fulfillment cart" that has (quantity, aisle, and refrigeration) for each item the customer is ordering. +Items should appear in _reverse_ alphabetical order. + +```python +>>> send_to_store({'Banana': 3, 'Apple': 2, 'Orange': 1, 'Milk': 2}, + {'Banana': ['Aisle 5', False], 'Apple': ['Aisle 4', False], 'Orange': ['Aisle 4', False], 'Milk': ['Aisle 2', True]}) +{'Orange': [1, 'Aisle 4', False], 'Milk': [2, 'Aisle 2', True], 'Banana': [3, 'Aisle 5', False], 'Apple': [2, 'Aisle 4', False]} +``` + +## 6. Update the Store Inventory to Reflect what a User Has Ordered. + +The app can't just place customer orders endlessly. +Eventually, the store is going to run out of various products. +So your app MVP needs to update the store inventory every time a user sends their order to the store. +Otherwise, customers will order products that aren't actually available. + +Create the function `update_store_inventory(<fulfillment_cart>, <store_inventory>)` that takes a "fulfillment cart" and a store inventory. +The function should reduce the store inventory amounts by the number "ordered" in the "fulfillment cart" and then return the updated store inventory. +Where a store item count falls to 0, the count should be replaced by the message 'Out of Stock'. + +```python +>>> update_store_inventory({'Orange': [1, 'Aisle 4', False], 'Milk': [2, 'Aisle 2', True], 'Banana': [3, 'Aisle 5', False], 'Apple': [2, 'Aisle 4', False]}, +{'Banana': [15, 'Aisle 5', False], 'Apple': [12, 'Aisle 4', False], 'Orange': [1, 'Aisle 4', False], 'Milk': [4, 'Aisle 2', True]}) + +{'Banana': [12, 'Aisle 5', False], 'Apple': [10, 'Aisle 4', False], 'Orange': ['Out of Stock', 'Aisle 4', False], 'Milk': [2, 'Aisle 2', True]} +``` + +[feature creep]: https://en.wikipedia.org/wiki/Feature_creep +[mvp]: https://en.wikipedia.org/wiki/Minimum_viable_product + +## Source + +### Created by + +- @meatball133 +- @BethanyG \ No newline at end of file diff --git a/python/mecha-munch-management/__pycache__/dict_methods.cpython-313.pyc b/python/mecha-munch-management/__pycache__/dict_methods.cpython-313.pyc new file mode 100644 index 0000000..9ef4e4c Binary files /dev/null and b/python/mecha-munch-management/__pycache__/dict_methods.cpython-313.pyc differ diff --git a/python/mecha-munch-management/__pycache__/dict_methods.cpython-314.pyc b/python/mecha-munch-management/__pycache__/dict_methods.cpython-314.pyc new file mode 100644 index 0000000..8f15861 Binary files /dev/null and b/python/mecha-munch-management/__pycache__/dict_methods.cpython-314.pyc differ diff --git a/python/mecha-munch-management/__pycache__/dict_methods_test.cpython-313-pytest-8.3.4.pyc b/python/mecha-munch-management/__pycache__/dict_methods_test.cpython-313-pytest-8.3.4.pyc new file mode 100644 index 0000000..8c62110 Binary files /dev/null and b/python/mecha-munch-management/__pycache__/dict_methods_test.cpython-313-pytest-8.3.4.pyc differ diff --git a/python/mecha-munch-management/__pycache__/dict_methods_test.cpython-314-pytest-9.1.0.pyc b/python/mecha-munch-management/__pycache__/dict_methods_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..8726b8a Binary files /dev/null and b/python/mecha-munch-management/__pycache__/dict_methods_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/mecha-munch-management/__pycache__/dict_methods_test_data.cpython-313.pyc b/python/mecha-munch-management/__pycache__/dict_methods_test_data.cpython-313.pyc new file mode 100644 index 0000000..0f7db8b Binary files /dev/null and b/python/mecha-munch-management/__pycache__/dict_methods_test_data.cpython-313.pyc differ diff --git a/python/mecha-munch-management/__pycache__/dict_methods_test_data.cpython-314.pyc b/python/mecha-munch-management/__pycache__/dict_methods_test_data.cpython-314.pyc new file mode 100644 index 0000000..cf5b332 Binary files /dev/null and b/python/mecha-munch-management/__pycache__/dict_methods_test_data.cpython-314.pyc differ diff --git a/python/mecha-munch-management/dict_methods.py b/python/mecha-munch-management/dict_methods.py new file mode 100644 index 0000000..e20c648 --- /dev/null +++ b/python/mecha-munch-management/dict_methods.py @@ -0,0 +1,93 @@ +"""Functions to manage a users shopping cart items.""" + +from re import fullmatch + + +def add_item(current_cart, items_to_add): + """Add items to shopping cart. + + :param current_cart: dict - the current shopping cart. + :param items_to_add: iterable - items to add to the cart. + :return: dict - the updated user cart dictionary. + """ + # create a new cart with items_to_add if current_cart is empty + # if current_cart == {}: + # current_cart = dict.fromkeys(items_to_add, 0) + # for item in items_to_add: + # current_cart[item] += 1 + # return current_cart + + # (after doing this i realized that the bellow code also addresses the + # concern of the current_cart being empty, so i commented out the code + # above) + + # increment item by one if item already exists in current_cart, + # otherwise add new item to current_cart with value of 1 + for item in items_to_add: + current_cart[item] = current_cart.get(item, 0) + 1 + return current_cart + + +def read_notes(notes): + """Create user cart from an iterable notes entry. + + :param notes: iterable of items to add to cart. + :return: dict - a user shopping cart dictionary. + """ + shopping_cart: dict = dict.fromkeys(notes, 0) + for item in notes: + shopping_cart[item] += 1 + return shopping_cart + + +def update_recipes(ideas, recipe_updates): + """Update the recipe ideas dictionary. + + :param ideas: dict - The "recipe ideas" dict. + :param recipe_updates: dict - dictionary with updates for the ideas section. + :return: dict - updated "recipe ideas" dict. + """ + ideas |= recipe_updates + return ideas + + +def sort_entries(cart): + """Sort a users shopping cart in alphabetically order. + + :param cart: dict - a users shopping cart dictionary. + :return: dict - users shopping cart sorted in alphabetical order. + """ + sorted_cart: dict = dict(sorted(cart.items())) + return sorted_cart + + +def send_to_store(cart, aisle_mapping): + """Combine users order to aisle and refrigeration information. + + :param cart: dict - users shopping cart dictionary. + :param aisle_mapping: dict - aisle and refrigeration information dictionary. + :return: dict - fulfillment dictionary ready to send to store. + """ + fulfillment: dict[str, list] = {} + for item in cart: + fulfillment[item] = [cart[item], + aisle_mapping[item][0], aisle_mapping[item][1]] + fulfillment = dict(sorted(fulfillment.items(), reverse=True)) + return fulfillment + + +def update_store_inventory(fulfillment_cart, store_inventory): + """Update store inventory levels with user order. + + :param fulfillment cart: dict - fulfillment cart to send to store. + :param store_inventory: dict - store available inventory + :return: dict - store_inventory updated. + """ + for item in fulfillment_cart: + new_stock = store_inventory[item][0] - fulfillment_cart[item][0] + store_inventory[item] = [ + "Out of Stock" if new_stock <= 0 else new_stock, + store_inventory[item][1], + store_inventory[item][2], + ] + return store_inventory diff --git a/python/mecha-munch-management/dict_methods_test.py b/python/mecha-munch-management/dict_methods_test.py new file mode 100644 index 0000000..4d8dab8 --- /dev/null +++ b/python/mecha-munch-management/dict_methods_test.py @@ -0,0 +1,94 @@ +import unittest +import pytest +from collections import OrderedDict +from dict_methods import ( + add_item, + read_notes, + update_recipes, + sort_entries, + send_to_store, + update_store_inventory, +) + +from dict_methods_test_data import ( + add_item_data, + read_notes_data, + update_recipes_data, + sort_entries_data, + send_to_store_data, + update_store_inventory_data, +) + +class MechaMunchManagementTest(unittest.TestCase): + + @pytest.mark.task(taskno=1) + def test_add_item(self): + for variant, (input_data, expected) in enumerate(add_item_data, start=1): + with self.subTest(f'variation #{variant}', input_data=input_data, expected=expected): + actual_result = add_item(input_data[0], input_data[1]) + error_msg= (f'Called add_item({input_data[0]}, {input_data[1]}). ' + f'The function returned {actual_result}, but the tests ' + f'expected: {expected} once the item was added.') + + self.assertEqual(actual_result, expected, msg=error_msg) + + @pytest.mark.task(taskno=2) + def test_read_notes(self): + for variant, (input_data, expected) in enumerate(read_notes_data, start=1): + with self.subTest(f'variation #{variant}', input_data=input_data, expected=expected): + actual_result = read_notes(input_data) + error_msg = (f'Called read_notes({input_data}). ' + f'The function returned {actual_result}, but the tests ' + f'expected: {expected} once the notes were read.') + + self.assertEqual(actual_result, expected, msg=error_msg) + + @pytest.mark.task(taskno=3) + def test_update_recipes(self): + for variant, (input_data, expected) in enumerate(update_recipes_data, start=1): + with self.subTest(f'variation #{variant}', input_data=input_data, expected=expected): + actual_result = update_recipes(input_data[0], input_data[1]) + error_msg = (f'Called update_recipes({input_data[0]}, {input_data[1]}). ' + f'The function returned {actual_result}, but the tests ' + f'expected: {expected} once the recipes were updated.') + + self.assertEqual(actual_result, expected, msg=error_msg) + + @pytest.mark.task(taskno=4) + def test_sort_entries(self): + for variant, (input_data, expected) in enumerate(sort_entries_data, start=1): + with self.subTest(f'variation #{variant}', input_data=input_data, expecred=expected): + actual_result = sort_entries(input_data) + error_msg = (f'Called sort_entries({input_data}). ' + f'The function returned {actual_result}, but the tests ' + f'expected: {expected} for the sorted entries.') + + # Because we are asserting equal, we need to convert to an OrderedDict. + # Regular dictionaries will compare equal even when they are ordered + # differently from one another. See https://stackoverflow.com/a/58961124 + self.assertEqual(OrderedDict(actual_result), OrderedDict(expected), msg=error_msg) + + @pytest.mark.task(taskno=5) + def test_send_to_store(self): + for variant, (input_data, expected) in enumerate(send_to_store_data, start=1): + with self.subTest(f'variation #{variant}', input_data=input_data, expected=expected): + actual_result = send_to_store(input_data[0], input_data[1]) + error_msg = (f'Called send_to_store({input_data[0]}, {input_data[1]}). ' + f'The function returned {actual_result}, but the tests ' + f'expected: {expected} as the fulfillment cart.') + + # Because we are asserting equal, we need to convert to an OrderedDict. + # Regular dictionaries will compare equal even when they are ordered + # differently from one another. See https://stackoverflow.com/a/58961124 + self.assertEqual(OrderedDict(actual_result), OrderedDict(expected), msg=error_msg) + + @pytest.mark.task(taskno=6) + def test_update_store_inventory(self): + for variant, (input_data, expected) in enumerate(update_store_inventory_data, start=1): + with self.subTest(f'variation #{variant}', input_data=input_data, expected=expected): + actual_result = update_store_inventory(input_data[0], input_data[1]) + error_msg = (f'Called update_store_inventory({input_data[0]}, {input_data[1]}). ' + f'The function returned {actual_result}, but the tests ' + f'expected: {expected} as the store inventory.') + + self.assertEqual(actual_result, expected, msg=error_msg) diff --git a/python/mecha-munch-management/dict_methods_test_data.py b/python/mecha-munch-management/dict_methods_test_data.py new file mode 100644 index 0000000..7914aaa --- /dev/null +++ b/python/mecha-munch-management/dict_methods_test_data.py @@ -0,0 +1,394 @@ +## add_item test cases## +add_item_inputs = [ + ({"Apple": 1, "Banana": 4}, ("Apple", "Banana", "Orange")), + ( + {"Orange": 1, "Raspberry": 1, "Blueberries": 10}, + ["Raspberry", "Blueberries", "Raspberry"], + ), + ( + {"Broccoli": 1, "Banana": 1}, + ("Broccoli", "Kiwi", "Kiwi", "Kiwi", "Melon", "Apple", "Banana", "Banana"), + ), +] + +add_item_outputs = [ + {"Apple": 2, "Banana": 5, "Orange": 1}, + {"Orange": 1, "Raspberry": 3, "Blueberries": 11}, + {"Broccoli": 2, "Banana": 3, "Kiwi": 3, "Melon": 1, "Apple": 1}, +] + +add_item_data = zip(add_item_inputs, add_item_outputs) + + +## read_notes test cases## +read_notes_inputs = [ + ("Apple", "Banana"), + ("Orange", "Raspberry", "Blueberries"), + ["Broccoli", "Kiwi", "Melon", "Apple", "Banana"], +] + +read_notes_outputs = [ + {"Apple": 1, "Banana": 1}, + {"Orange": 1, "Raspberry": 1, "Blueberries": 1}, + {"Broccoli": 1, "Kiwi": 1, "Melon": 1, "Apple": 1, "Banana": 1}, +] + +read_notes_data = zip(read_notes_inputs, read_notes_outputs) + + +## update_recipes test cases## +update_recipes_inputs = [ + ( + { + "Banana Bread": { + "Banana": 1, + "Apple": 1, + "Walnuts": 1, + "Flour": 1, + "Eggs": 2, + "Butter": 1, + }, + "Raspberry Pie": { + "Raspberry": 1, + "Orange": 1, + "Pie Crust": 1, + "Cream Custard": 1, + }, + }, + ( + ( + "Banana Bread", + { + "Banana": 4, + "Walnuts": 2, + "Flour": 1, + "Butter": 1, + "Milk": 2, + "Eggs": 3, + }, + ), + ), + ), + ( + { + "Apple Pie": {"Apple": 1, "Pie Crust": 1, "Cream Custard": 1}, + "Blueberry Pie": {"Blueberries": 1, "Pie Crust": 1, "Cream Custard": 1}, + }, + ( + ("Blueberry Pie", {"Blueberries": 2, + "Pie Crust": 1, "Cream Custard": 1}), + ("Apple Pie", {"Apple": 1, "Pie Crust": 1, "Cream Custard": 1}), + ), + ), + ( + { + "Banana Bread": { + "Banana": 1, + "Apple": 1, + "Walnuts": 1, + "Flour": 1, + "Eggs": 2, + "Butter": 1, + }, + "Raspberry Pie": { + "Raspberry": 1, + "Orange": 1, + "Pie Crust": 1, + "Cream Custard": 1, + }, + "Pasta Primavera": { + "Eggs": 1, + "Carrots": 1, + "Spinach": 2, + "Tomatoes": 3, + "Parmesan": 2, + "Milk": 1, + "Onion": 1, + }, + }, + ( + ( + "Raspberry Pie", + { + "Raspberry": 3, + "Orange": 1, + "Pie Crust": 1, + "Cream Custard": 1, + "Whipped Cream": 2, + }, + ), + ( + "Pasta Primavera", + { + "Eggs": 1, + "Mixed Veggies": 2, + "Parmesan": 2, + "Milk": 1, + "Spinach": 1, + "Bread Crumbs": 1, + }, + ), + ( + "Blueberry Crumble", + { + "Blueberries": 2, + "Whipped Creme": 2, + "Granola Topping": 2, + "Yogurt": 3, + }, + ), + ), + ), +] + +update_recipes_outputs = [ + { + "Banana Bread": { + "Banana": 4, + "Walnuts": 2, + "Flour": 1, + "Butter": 1, + "Milk": 2, + "Eggs": 3, + }, + "Raspberry Pie": { + "Raspberry": 1, + "Orange": 1, + "Pie Crust": 1, + "Cream Custard": 1, + }, + }, + { + "Apple Pie": {"Apple": 1, "Pie Crust": 1, "Cream Custard": 1}, + "Blueberry Pie": {"Blueberries": 2, "Pie Crust": 1, "Cream Custard": 1}, + }, + { + "Banana Bread": { + "Banana": 1, + "Apple": 1, + "Walnuts": 1, + "Flour": 1, + "Eggs": 2, + "Butter": 1, + }, + "Raspberry Pie": { + "Raspberry": 3, + "Orange": 1, + "Pie Crust": 1, + "Cream Custard": 1, + "Whipped Cream": 2, + }, + "Pasta Primavera": { + "Eggs": 1, + "Mixed Veggies": 2, + "Parmesan": 2, + "Milk": 1, + "Spinach": 1, + "Bread Crumbs": 1, + }, + "Blueberry Crumble": { + "Blueberries": 2, + "Whipped Creme": 2, + "Granola Topping": 2, + "Yogurt": 3, + }, + }, +] + +update_recipes_data = zip(update_recipes_inputs, update_recipes_outputs) + + +## sort_entries test cases## +sort_entries_inputs = [ + {"Banana": 4, "Apple": 2, "Orange": 1, "Pear": 12}, + {"Apple": 3, "Orange": 5, "Banana": 1, "Avocado": 2}, + {"Orange": 3, "Banana": 2, "Apple": 1}, + { + "Apple": 2, + "Raspberry": 2, + "Blueberries": 5, + "Broccoli": 2, + "Kiwi": 1, + "Melon": 4, + }, +] + +sort_entries_outputs = [ + {"Apple": 2, "Banana": 4, "Orange": 1, "Pear": 12}, + {"Apple": 3, "Avocado": 2, "Banana": 1, "Orange": 5}, + {"Apple": 1, "Banana": 2, "Orange": 3}, + { + "Apple": 2, + "Blueberries": 5, + "Broccoli": 2, + "Kiwi": 1, + "Melon": 4, + "Raspberry": 2, + }, +] + + +sort_entries_data = zip(sort_entries_inputs, sort_entries_outputs) + + +## send_to_store test cases## +send_to_store_inputs = [ + ( + {"Banana": 3, "Apple": 2, "Orange": 1, "Milk": 2}, + { + "Banana": ["Aisle 5", False], + "Apple": ["Aisle 4", False], + "Orange": ["Aisle 4", False], + "Milk": ["Aisle 2", True], + }, + ), + ( + {"Kiwi": 3, "Juice": 5, "Yoghurt": 2, "Milk": 5}, + { + "Kiwi": ["Aisle 6", False], + "Juice": ["Aisle 5", False], + "Yoghurt": ["Aisle 2", True], + "Milk": ["Aisle 2", True], + }, + ), + ( + { + "Apple": 2, + "Raspberry": 2, + "Blueberries": 5, + "Broccoli": 2, + "Kiwi": 1, + "Melon": 4, + }, + { + "Apple": ["Aisle 1", False], + "Raspberry": ["Aisle 6", False], + "Blueberries": ["Aisle 6", False], + "Broccoli": ["Aisle 3", False], + "Kiwi": ["Aisle 6", False], + "Melon": ["Aisle 6", False], + }, + ), + ( + {"Orange": 1}, + { + "Banana": ["Aisle 5", False], + "Apple": ["Aisle 4", False], + "Orange": ["Aisle 4", False], + "Milk": ["Aisle 2", True], + }, + ), + ( + {"Banana": 3, "Apple": 2, "Orange": 1}, + { + "Banana": ["Aisle 5", False], + "Apple": ["Aisle 4", False], + "Orange": ["Aisle 4", False], + "Milk": ["Aisle 2", True], + }, + ), +] + +send_to_store_outputs = [ + { + "Orange": [1, "Aisle 4", False], + "Milk": [2, "Aisle 2", True], + "Banana": [3, "Aisle 5", False], + "Apple": [2, "Aisle 4", False], + }, + { + "Yoghurt": [2, "Aisle 2", True], + "Milk": [5, "Aisle 2", True], + "Kiwi": [3, "Aisle 6", False], + "Juice": [5, "Aisle 5", False], + }, + { + "Raspberry": [2, "Aisle 6", False], + "Melon": [4, "Aisle 6", False], + "Kiwi": [1, "Aisle 6", False], + "Broccoli": [2, "Aisle 3", False], + "Blueberries": [5, "Aisle 6", False], + "Apple": [2, "Aisle 1", False], + }, + {"Orange": [1, "Aisle 4", False]}, + { + "Orange": [1, "Aisle 4", False], + "Banana": [3, "Aisle 5", False], + "Apple": [2, "Aisle 4", False], + }, +] + +send_to_store_data = zip(send_to_store_inputs, send_to_store_outputs) + + +## update_store_inventory test cases## +update_store_inventory_inputs = [ + ( + { + "Orange": [1, "Aisle 4", False], + "Milk": [2, "Aisle 2", True], + "Banana": [3, "Aisle 5", False], + "Apple": [2, "Aisle 4", False], + }, + { + "Banana": [15, "Aisle 5", False], + "Apple": [12, "Aisle 4", False], + "Orange": [1, "Aisle 4", False], + "Milk": [4, "Aisle 2", True], + }, + ), + ( + {"Kiwi": [3, "Aisle 6", False]}, + { + "Kiwi": [3, "Aisle 6", False], + "Juice": [5, "Aisle 5", False], + "Yoghurt": [2, "Aisle 2", True], + "Milk": [5, "Aisle 2", True], + }, + ), + ( + { + "Kiwi": [1, "Aisle 6", False], + "Melon": [4, "Aisle 6", False], + "Apple": [2, "Aisle 1", False], + "Raspberry": [2, "Aisle 6", False], + "Blueberries": [5, "Aisle 6", False], + "Broccoli": [1, "Aisle 3", False], + }, + { + "Apple": [2, "Aisle 1", False], + "Raspberry": [5, "Aisle 6", False], + "Blueberries": [10, "Aisle 6", False], + "Broccoli": [4, "Aisle 3", False], + "Kiwi": [1, "Aisle 6", False], + "Melon": [8, "Aisle 6", False], + }, + ), +] + +update_store_inventory_outputs = [ + { + "Banana": [12, "Aisle 5", False], + "Apple": [10, "Aisle 4", False], + "Orange": ["Out of Stock", "Aisle 4", False], + "Milk": [2, "Aisle 2", True], + }, + { + "Juice": [5, "Aisle 5", False], + "Yoghurt": [2, "Aisle 2", True], + "Milk": [5, "Aisle 2", True], + "Kiwi": ["Out of Stock", "Aisle 6", False], + }, + { + "Kiwi": ["Out of Stock", "Aisle 6", False], + "Melon": [4, "Aisle 6", False], + "Apple": ["Out of Stock", "Aisle 1", False], + "Raspberry": [3, "Aisle 6", False], + "Blueberries": [5, "Aisle 6", False], + "Broccoli": [3, "Aisle 3", False], + }, +] + +update_store_inventory_data = zip( + update_store_inventory_inputs, update_store_inventory_outputs +) diff --git a/python/meltdown-mitigation/.exercism/config.json b/python/meltdown-mitigation/.exercism/config.json new file mode 100644 index 0000000..eb88d8b --- /dev/null +++ b/python/meltdown-mitigation/.exercism/config.json @@ -0,0 +1,22 @@ +{ + "authors": [ + "sachsom95", + "BethanyG" + ], + "contributors": [ + "kbuc" + ], + "files": { + "solution": [ + "conditionals.py" + ], + "test": [ + "conditionals_test.py" + ], + "exemplar": [ + ".meta/exemplar.py" + ] + }, + "icon": "circular-buffer", + "blurb": "Learn about conditionals and avoid a meltdown by developing a simple control system for a Nuclear Reactor." +} diff --git a/python/meltdown-mitigation/.exercism/metadata.json b/python/meltdown-mitigation/.exercism/metadata.json new file mode 100644 index 0000000..780519e --- /dev/null +++ b/python/meltdown-mitigation/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"meltdown-mitigation","id":"e493eeb176774ffeb8aa7afb365cf975","url":"https://exercism.org/tracks/python/exercises/meltdown-mitigation","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/meltdown-mitigation/HELP.md b/python/meltdown-mitigation/HELP.md new file mode 100644 index 0000000..f931e6c --- /dev/null +++ b/python/meltdown-mitigation/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +<br> + +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit conditionals.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/meltdown-mitigation/HINTS.md b/python/meltdown-mitigation/HINTS.md new file mode 100644 index 0000000..bee2779 --- /dev/null +++ b/python/meltdown-mitigation/HINTS.md @@ -0,0 +1,50 @@ +# Hints + +## General + +- The Python Docs on [Control Flow Tools][control flow tools] and the Real Python tutorial on [conditionals][real python conditionals] are great places to start. +- The Python Docs on [Boolean Operations][boolean operations] can be a great refresher on `bools`, as can the Real Python tutorial on [booleans][python booleans]. +- The Python Docs on [Comparisons][comparisons] and [comparisons examples][python comparisons examples] can be a great refresher for comparisons. + +## 1. Check for criticality + +- Comparison operators ([comparisons][comparisons review]) and boolean operations ([concept:python/bools]()) can be combined and used with conditionals. +- Conditional expressions must evaluate to `True` or `False`. +- `else` can be used for a code block that will execute when all conditional tests return `False`. + + ```python + >>> item = 'blue' + >>> item_2 = 'green' + + >>> if len(item) >= 3 and len(item_2) < 5: + print('Both pass the test!') + elif len(item) >= 3 or len(item_2) < 5: + print('One passes the test!') + else: + print('None pass the test!') + ... + One passes the test! + ``` + +## 2. Determine the Power output range + +- Comparison operators can be combined and used with conditionals. +- Any number of `elif` statements can be used as decision "branches". +- Each "branch" can have a separate `return`, although it might be considered "bad form" by linting tools. +- If the linter complains, consider assigning the output of a branch to a common variable, and then `return`ing that variable. + +## 3. Fail Safe Mechanism + +- Comparison operators can be combined and used with conditionals. +- Any number of `elif` statements can be used as decision "branches". +- Each "branch" can have a separate `return`, although it might be considered "bad form" by linting tools. +- If the linter complains, consider assigning the output of a branch to a common variable, and then `return`ing that variable. + + +[boolean operations]: https://docs.python.org/3/library/stdtypes.html#boolean-operations-and-or-not +[comparisons review]: https://www.learnpython.dev/02-introduction-to-python/090-boolean-logic/20-comparisons/ +[comparisons]: https://docs.python.org/3/library/stdtypes.html#comparisons +[control flow tools]: https://docs.python.org/3/tutorial/controlflow.html +[python booleans]: https://realpython.com/python-boolean/ +[python comparisons examples]: https://www.tutorialspoint.com/python/comparison_operators_example.htm +[real python conditionals]: https://realpython.com/python-conditional-statements/ \ No newline at end of file diff --git a/python/meltdown-mitigation/README.md b/python/meltdown-mitigation/README.md new file mode 100644 index 0000000..d16704e --- /dev/null +++ b/python/meltdown-mitigation/README.md @@ -0,0 +1,172 @@ +# Meltdown Mitigation + +Welcome to Meltdown Mitigation on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. +If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :) + +## Introduction + +In Python, [`if`][if statement], `elif` (_a contraction of 'else and if'_) and `else` statements are used to [control the flow][control flow tools] of execution and make decisions in a program. +Unlike many other programming languages, Python versions 3.9 and below do not offer a formal case-switch statement, instead using multiple `elif` statements to serve a similar purpose. + +Python 3.10 introduces a variant case-switch statement called `structural pattern matching`, which will be covered separately in another concept. + +Conditional statements use expressions that must resolve to `True` or `False` -- either by returning a `bool` type directly, or by evaluating as ["truthy" or "falsy"][truth value testing]. + +```python +x = 10 +y = 5 + +# The comparison '>' returns the bool 'True', +# so the statement is printed. +if x > y: + print("x is greater than y") +... +>>> x is greater than y +``` + +When paired with `if`, an optional `else` code block will execute when the original `if` condition evaluates to `False`: + +```python +x = 5 +y = 10 + +# The comparison '>' here returns the bool 'False', +# so the 'else' block is executed instead of the 'if' block. +if x > y: + print("x is greater than y") +else: + print("y is greater than x") +... +>>> y is greater than x +``` + +`elif` allows for multiple evaluations/branches. + +```python +x = 5 +y = 10 +z = 20 + +# The 'elif' statement allows for the checking of more conditions. +if x > y: + print("x is greater than y and z") +elif y > z: + print("y is greater than x and z") +else: + print("z is greater than x and y") +... +>>> z is greater than x and y +``` + +[Boolean operations][boolean operations] and [comparisons][comparisons] can be combined with conditionals for more complex testing: + +```python +>>> def classic_fizzbuzz(number): + if number % 3 == 0 and number % 5 == 0: + say = 'FizzBuzz!' + elif number % 5 == 0: + say = 'Buzz!' + elif number % 3 == 0: + say = 'Fizz!' + else: + say = str(number) + + return say + +>>> classic_fizzbuzz(15) +'FizzBuzz!' + +>>> classic_fizzbuzz(13) +'13' +``` + +[boolean operations]: https://docs.python.org/3/library/stdtypes.html#boolean-operations-and-or-not +[comparisons]: https://docs.python.org/3/library/stdtypes.html#comparisons +[control flow tools]: https://docs.python.org/3/tutorial/controlflow.html#more-control-flow-tools +[if statement]: https://docs.python.org/3/reference/compound_stmts.html#the-if-statement +[truth value testing]: https://docs.python.org/3/library/stdtypes.html#truth-value-testing + +## Instructions + +In this exercise, we'll develop a simple control system for a nuclear reactor. + +For a reactor to produce the power it must be in a state of _criticality_. +If the reactor is in a state less than criticality, it can become damaged. +If the reactor state goes beyond criticality, it can overload and result in a meltdown. +We want to mitigate the chances of meltdown and correctly manage reactor state. + +The following three tasks are all related to writing code for maintaining ideal reactor state. + +## 1. Check for criticality + +The first thing a control system has to do is check if the reactor is balanced in criticality. +A reactor is said to be critical if it satisfies the following conditions: + +- The temperature is less than 800 K. +- The number of neutrons emitted per second is greater than 500. +- The product of temperature and neutrons emitted per second is less than 500000. + +Implement the function `is_criticality_balanced()` that takes `temperature` measured in kelvin and `neutrons_emitted` as parameters, and returns `True` if the criticality conditions are met, `False` if not. + +```python +>>> is_criticality_balanced(750, 600) +True +``` + +## 2. Determine the Power output range + +Once the reactor has started producing power its efficiency needs to be determined. +Efficiency can be grouped into 4 bands: + +1. `green` -> efficiency of 80% or more, +2. `orange` -> efficiency of less than 80% but at least 60%, +3. `red` -> efficiency below 60%, but still 30% or more, +4. `black` -> less than 30% efficient. + +The percentage value can be calculated as `(generated_power/theoretical_max_power)*100` +where `generated_power` = `voltage` * `current`. +Note that the percentage value is usually not an integer number, so make sure to consider the +proper use of the `<` and `<=` comparisons. + +Implement the function `reactor_efficiency(<voltage>, <current>, <theoretical_max_power>)`, with three parameters: `voltage`, +`current`, and `theoretical_max_power`. +This function should return the efficiency band of the reactor : 'green', 'orange', 'red', or 'black'. + +```python +>>> reactor_efficiency(200,50,15000) +'orange' +``` + +## 3. Fail Safe Mechanism + +Your final task involves creating a fail-safe mechanism to avoid overload and meltdown. +This mechanism will determine if the reactor is below, at, or above the ideal criticality threshold. +Criticality can then be increased, decreased, or stopped by inserting (or removing) control rods into the reactor. + +Implement the function called `fail_safe()`, which takes 3 parameters: `temperature` measured in kelvin, +`neutrons_produced_per_second`, and `threshold`, and outputs a status code for the reactor. + +- If `temperature * neutrons_produced_per_second` < 90% of `threshold`, output a status code of 'LOW' + indicating that control rods must be removed to produce power. + +- If the value `temperature * neutrons_produced_per_second` is within 10% of the `threshold` (so either 0-10% less than the threshold, at the threshold, or 0-10% greater than the threshold), the reactor is in _criticality_ and the status code of 'NORMAL' should be output, indicating that the reactor is in optimum condition and control rods are in an ideal position. + +- If `temperature * neutrons_produced_per_second` is not in the above-stated ranges, the reactor is + going into meltdown and a status code of 'DANGER' must be passed to immediately shut down the reactor. + +```python +>>> fail_safe(temperature=1000, neutrons_produced_per_second=30, threshold=5000) +'DANGER' +``` + +## Source + +### Created by + +- @sachsom95 +- @BethanyG + +### Contributed to by + +- @kbuc \ No newline at end of file diff --git a/python/meltdown-mitigation/__pycache__/conditionals.cpython-313.pyc b/python/meltdown-mitigation/__pycache__/conditionals.cpython-313.pyc new file mode 100644 index 0000000..252c841 Binary files /dev/null and b/python/meltdown-mitigation/__pycache__/conditionals.cpython-313.pyc differ diff --git a/python/meltdown-mitigation/__pycache__/conditionals.cpython-314.pyc b/python/meltdown-mitigation/__pycache__/conditionals.cpython-314.pyc new file mode 100644 index 0000000..d1a9f70 Binary files /dev/null and b/python/meltdown-mitigation/__pycache__/conditionals.cpython-314.pyc differ diff --git a/python/meltdown-mitigation/__pycache__/conditionals_test.cpython-313-pytest-8.3.4.pyc b/python/meltdown-mitigation/__pycache__/conditionals_test.cpython-313-pytest-8.3.4.pyc new file mode 100644 index 0000000..2d9cdf6 Binary files /dev/null and b/python/meltdown-mitigation/__pycache__/conditionals_test.cpython-313-pytest-8.3.4.pyc differ diff --git a/python/meltdown-mitigation/__pycache__/conditionals_test.cpython-314-pytest-9.1.0.pyc b/python/meltdown-mitigation/__pycache__/conditionals_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..77056bf Binary files /dev/null and b/python/meltdown-mitigation/__pycache__/conditionals_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/meltdown-mitigation/conditionals.py b/python/meltdown-mitigation/conditionals.py new file mode 100644 index 0000000..0d2a536 --- /dev/null +++ b/python/meltdown-mitigation/conditionals.py @@ -0,0 +1,75 @@ +"""Functions to prevent a nuclear meltdown.""" + + +def is_criticality_balanced(temperature, neutrons_emitted): + """Verify criticality is balanced. + + :param temperature: int or float - temperature value in kelvin. + :param neutrons_emitted: int or float - number of neutrons emitted per second. + :return: bool - is criticality balanced? + + A reactor is said to be critical if it satisfies the following conditions: + - The temperature is less than 800 K. + - The number of neutrons emitted per second is greater than 500. + - The product of temperature and neutrons emitted per second is less than 500000. + """ + if temperature >= 800: + return False + if neutrons_emitted <= 500: + return False + if temperature * neutrons_emitted >= 500000: + return False + return True + + +def reactor_efficiency(voltage, current, theoretical_max_power): + """Assess reactor efficiency zone. + + :param voltage: int or float - voltage value. + :param current: int or float - current value. + :param theoretical_max_power: int or float - power that corresponds to a 100% efficiency. + :return: str - one of ('green', 'orange', 'red', or 'black'). + pass + Efficiency can be grouped into 4 bands: + + 1. green -> efficiency of 80% or more, + 2. orange -> efficiency of less than 80% but at least 60%, + 3. red -> efficiency below 60%, but still 30% or more, + 4. black -> less than 30% efficient. + + The percentage value is calculated as + (generated power/ theoretical max power)*100 + where generated power = voltage * current + """ + efficiency_colour: str = "" + efficiency_percentage = ((voltage * current) / theoretical_max_power) * 100 + if efficiency_percentage >= 80: + efficiency_colour = "green" + elif efficiency_percentage >= 60: + efficiency_colour = "orange" + elif efficiency_percentage >= 30: + efficiency_colour = "red" + else: + efficiency_colour = "black" + return efficiency_colour + + +def fail_safe(temperature, neutrons_produced_per_second, threshold): + """Assess and return status code for the reactor. + + :param temperature: int or float - value of the temperature in kelvin. + :param neutrons_produced_per_second: int or float - neutron flux. + :param threshold: int or float - threshold for category. + :return: str - one of ('LOW', 'NORMAL', 'DANGER'). + + 1. 'LOW' -> `temperature * neutrons per second` < 90% of `threshold` + 2. 'NORMAL' -> `temperature * neutrons per second` +/- 10% of `threshold` + 3. 'DANGER' -> `temperature * neutrons per second` is not in the above-stated ranges + """ + temp_and_neutrons_level: float = temperature * neutrons_produced_per_second + if (temp_and_neutrons_level / threshold) < 0.9: + return "LOW" + elif (temp_and_neutrons_level / threshold) < 1.10: + return "NORMAL" + else: + return "DANGER" diff --git a/python/meltdown-mitigation/conditionals_test.py b/python/meltdown-mitigation/conditionals_test.py new file mode 100644 index 0000000..5e48ca3 --- /dev/null +++ b/python/meltdown-mitigation/conditionals_test.py @@ -0,0 +1,82 @@ +import unittest +import pytest +from conditionals import (is_criticality_balanced, + reactor_efficiency, + fail_safe) + + +class MeltdownMitigationTest(unittest.TestCase): + """Test cases for Meltdown mitigation exercise. + """ + + @pytest.mark.task(taskno=1) + def test_is_criticality_balanced(self): + """Testing border cases around typical points. + + T, n == (800, 500), (625, 800), (500, 1000), etc. + + """ + + test_data = ((750, 650, True), (799, 501, True), (500, 600, True), + (1000, 800, False), (800, 500, False), (800, 500.01, False), + (799.99, 500, False), (500.01, 999.99, False), (625, 800, False), + (625.99, 800, False), (625.01, 799.99, False), (799.99, 500.01, True), + (624.99, 799.99, True), (500, 1000, False), (500.01, 1000, False), + (499.99, 1000, True)) + + for variant, data in enumerate(test_data, start=1): + temp, neutrons_emitted, expected = data + with self.subTest(f'variation #{variant}', temp=temp, neutrons_emitted=neutrons_emitted, expected=expected): + + # pylint: disable=assignment-from-no-return + actual_result = is_criticality_balanced(temp, neutrons_emitted) + failure_message = (f'Called is_criticality_balanced({temp}, {neutrons_emitted}). ' + f' The function returned {actual_result}, ' + f'but the test expected {expected} as the return value.') + + self.assertEqual(actual_result, expected, failure_message) + + @pytest.mark.task(taskno=2) + def test_reactor_efficiency(self): + voltage = 10 + theoretical_max_power = 10000 + + # The numbers are chosen so that current == 10 x percentage + test_data = ((1000, 'green'), (999, 'green'), (800, 'green'), + (799, 'orange'), (700, 'orange'), (600, 'orange'), + (599, 'red'), (560, 'red'), (400, 'red'), (300, 'red'), + (299, 'black'), (200, 'black'), (0, 'black')) + + for variant, data in enumerate(test_data, start=1): + current, expected = data + with self.subTest(f'variation #{variant}', voltage=voltage, current=current, + theoretical_max_power=theoretical_max_power, expected=expected): + + # pylint: disable=assignment-from-no-return + actual_result = reactor_efficiency(voltage, current, theoretical_max_power) + failure_message =(f'Called reactor_efficiency({voltage}, {current}, {theoretical_max_power}). ' + f'The function returned {actual_result}, ' + f'but the test expected {expected} as the return value.') + + self.assertEqual(actual_result, expected, failure_message) + + @pytest.mark.task(taskno=3) + def test_fail_safe(self): + temp = 10 + threshold = 10000 + test_data = ((399, 'LOW'), (300, 'LOW'), (1, 'LOW'), + (0, 'LOW'), (901, 'NORMAL'), (1000, 'NORMAL'), + (1099, 'NORMAL'), (899, 'LOW'), (700, 'LOW'), + (400, 'LOW'), (1101, 'DANGER'), (1200, 'DANGER')) + + for variant, (neutrons_per_second, expected) in enumerate(test_data, start=1): + with self.subTest(f'variation #{variant}', temp=temp, neutrons_per_second=neutrons_per_second, + threshold=threshold, expected=expected): + + # pylint: disable=assignment-from-no-return + actual_result = fail_safe(temp, neutrons_per_second, threshold) + failure_message = (f'Called fail_safe({temp}, {neutrons_per_second}, {threshold}). ' + f'The function returned {actual_result}, ' + f'but the test expected {expected} as the return value.') + + self.assertEqual(actual_result, expected, failure_message) diff --git a/python/pangram/.exercism/config.json b/python/pangram/.exercism/config.json new file mode 100644 index 0000000..3d57bb9 --- /dev/null +++ b/python/pangram/.exercism/config.json @@ -0,0 +1,34 @@ +{ + "authors": [ + "behrtam" + ], + "contributors": [ + "cmccandless", + "Dog", + "Grociu", + "helenst", + "ikhadykin", + "luoken", + "mtroiani", + "N-Parsons", + "olufotebig", + "patricksjackson", + "pheanex", + "thomasjpfan", + "tqa236" + ], + "files": { + "solution": [ + "pangram.py" + ], + "test": [ + "pangram_test.py" + ], + "example": [ + ".meta/example.py" + ] + }, + "blurb": "Determine if a sentence is a pangram.", + "source": "Wikipedia", + "source_url": "https://en.wikipedia.org/wiki/Pangram" +} diff --git a/python/pangram/.exercism/metadata.json b/python/pangram/.exercism/metadata.json new file mode 100644 index 0000000..e10f9c9 --- /dev/null +++ b/python/pangram/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"pangram","id":"24c4fa654a374355a777e28ba5bf8366","url":"https://exercism.org/tracks/python/exercises/pangram","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/pangram/HELP.md b/python/pangram/HELP.md new file mode 100644 index 0000000..45b92b6 --- /dev/null +++ b/python/pangram/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +<br> + +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit pangram.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/pangram/README.md b/python/pangram/README.md new file mode 100644 index 0000000..fb1a1f2 --- /dev/null +++ b/python/pangram/README.md @@ -0,0 +1,56 @@ +# Pangram + +Welcome to Pangram on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Introduction + +You work for a company that sells fonts through their website. +They'd like to show a different sentence each time someone views a font on their website. +To give a comprehensive sense of the font, the random sentences should use **all** the letters in the English alphabet. + +They're running a competition to get suggestions for sentences that they can use. +You're in charge of checking the submissions to see if they are valid. + +~~~~exercism/note +Pangram comes from Greek, παν γράμμα, pan gramma, which means "every letter". + +The best known English pangram is: + +> The quick brown fox jumps over the lazy dog. +~~~~ + +## Instructions + +Your task is to figure out if a sentence is a pangram. + +A pangram is a sentence using every letter of the alphabet at least once. +It is case insensitive, so it doesn't matter if a letter is lower-case (e.g. `k`) or upper-case (e.g. `K`). + +For this exercise, a sentence is a pangram if it contains each of the 26 letters in the English alphabet. + +## Source + +### Created by + +- @behrtam + +### Contributed to by + +- @cmccandless +- @Dog +- @Grociu +- @helenst +- @ikhadykin +- @luoken +- @mtroiani +- @N-Parsons +- @olufotebig +- @patricksjackson +- @pheanex +- @thomasjpfan +- @tqa236 + +### Based on + +Wikipedia - https://en.wikipedia.org/wiki/Pangram \ No newline at end of file diff --git a/python/pangram/__pycache__/pangram.cpython-313.pyc b/python/pangram/__pycache__/pangram.cpython-313.pyc new file mode 100644 index 0000000..86eb73d Binary files /dev/null and b/python/pangram/__pycache__/pangram.cpython-313.pyc differ diff --git a/python/pangram/__pycache__/pangram.cpython-314.pyc b/python/pangram/__pycache__/pangram.cpython-314.pyc new file mode 100644 index 0000000..9a2746c Binary files /dev/null and b/python/pangram/__pycache__/pangram.cpython-314.pyc differ diff --git a/python/pangram/__pycache__/pangram_test.cpython-313-pytest-8.3.4.pyc b/python/pangram/__pycache__/pangram_test.cpython-313-pytest-8.3.4.pyc new file mode 100644 index 0000000..926c568 Binary files /dev/null and b/python/pangram/__pycache__/pangram_test.cpython-313-pytest-8.3.4.pyc differ diff --git a/python/pangram/__pycache__/pangram_test.cpython-314-pytest-9.1.0.pyc b/python/pangram/__pycache__/pangram_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..f6ddde8 Binary files /dev/null and b/python/pangram/__pycache__/pangram_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/pangram/pangram.py b/python/pangram/pangram.py new file mode 100644 index 0000000..9e2d41c --- /dev/null +++ b/python/pangram/pangram.py @@ -0,0 +1,7 @@ +def is_pangram(sentence): + # 26 letters in the alphabet 'A' is 65 and 'Z' is 90 + alphabet_letters: list = [chr(letter) for letter in range(ord("a"), ord("z") + 1)] + for letter in alphabet_letters: + if letter not in sentence.lower(): + return False + return True diff --git a/python/pangram/pangram_test.py b/python/pangram/pangram_test.py new file mode 100644 index 0000000..09e303d --- /dev/null +++ b/python/pangram/pangram_test.py @@ -0,0 +1,54 @@ +# These tests are auto-generated with test data from: +# https://github.com/exercism/problem-specifications/tree/main/exercises/pangram/canonical-data.json +# File last updated on 2023-07-19 + +import unittest + +from pangram import ( + is_pangram, +) + + +class PangramTest(unittest.TestCase): + def test_empty_sentence(self): + self.assertIs(is_pangram(""), False) + + def test_perfect_lower_case(self): + self.assertIs(is_pangram("abcdefghijklmnopqrstuvwxyz"), True) + + def test_only_lower_case(self): + self.assertIs(is_pangram("the quick brown fox jumps over the lazy dog"), True) + + def test_missing_the_letter_x(self): + self.assertIs( + is_pangram("a quick movement of the enemy will jeopardize five gunboats"), + False, + ) + + def test_missing_the_letter_h(self): + self.assertIs(is_pangram("five boxing wizards jump quickly at it"), False) + + def test_with_underscores(self): + self.assertIs(is_pangram("the_quick_brown_fox_jumps_over_the_lazy_dog"), True) + + def test_with_numbers(self): + self.assertIs( + is_pangram("the 1 quick brown fox jumps over the 2 lazy dogs"), True + ) + + def test_missing_letters_replaced_by_numbers(self): + self.assertIs(is_pangram("7h3 qu1ck brown fox jumps ov3r 7h3 lazy dog"), False) + + def test_mixed_case_and_punctuation(self): + self.assertIs(is_pangram('"Five quacking Zephyrs jolt my wax bed."'), True) + + def test_a_m_and_a_m_are_26_different_characters_but_not_a_pangram(self): + self.assertIs(is_pangram("abcdefghijklm ABCDEFGHIJKLM"), False) + + # Additional tests for this track + + def test_sentence_without_lower_bound(self): + self.assertIs(is_pangram("bcdefghijklmnopqrstuvwxyz"), False) + + def test_sentence_without_upper_bound(self): + self.assertIs(is_pangram("abcdefghijklmnopqrstuvwxy"), False) diff --git a/python/perfect-numbers/.exercism/config.json b/python/perfect-numbers/.exercism/config.json new file mode 100644 index 0000000..a77ccea --- /dev/null +++ b/python/perfect-numbers/.exercism/config.json @@ -0,0 +1,31 @@ +{ + "authors": [ + "behrtam" + ], + "contributors": [ + "cmccandless", + "Dog", + "emerali", + "ikhadykin", + "N-Parsons", + "olufotebig", + "pheanex", + "saurabhchalke", + "smalley", + "tqa236" + ], + "files": { + "solution": [ + "perfect_numbers.py" + ], + "test": [ + "perfect_numbers_test.py" + ], + "example": [ + ".meta/example.py" + ] + }, + "blurb": "Determine if a number is perfect, abundant, or deficient based on Nicomachus' (60 - 120 CE) classification scheme for positive integers.", + "source": "Taken from Chapter 2 of Functional Thinking by Neal Ford.", + "source_url": "https://www.oreilly.com/library/view/functional-thinking/9781449365509/" +} diff --git a/python/perfect-numbers/.exercism/metadata.json b/python/perfect-numbers/.exercism/metadata.json new file mode 100644 index 0000000..1fe63cf --- /dev/null +++ b/python/perfect-numbers/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"perfect-numbers","id":"effeada50c8449bb9bdda35ab14b2a88","url":"https://exercism.org/tracks/python/exercises/perfect-numbers","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/perfect-numbers/HELP.md b/python/perfect-numbers/HELP.md new file mode 100644 index 0000000..3e978c1 --- /dev/null +++ b/python/perfect-numbers/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +<br> + +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit perfect_numbers.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/perfect-numbers/README.md b/python/perfect-numbers/README.md new file mode 100644 index 0000000..f58105a --- /dev/null +++ b/python/perfect-numbers/README.md @@ -0,0 +1,80 @@ +# Perfect Numbers + +Welcome to Perfect Numbers on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Instructions + +Determine if a number is perfect, abundant, or deficient based on Nicomachus' (60 - 120 CE) classification scheme for positive integers. + +The Greek mathematician [Nicomachus][nicomachus] devised a classification scheme for positive integers, identifying each as belonging uniquely to the categories of [perfect](#perfect), [abundant](#abundant), or [deficient](#deficient) based on their [aliquot sum][aliquot-sum]. +The _aliquot sum_ is defined as the sum of the factors of a number not including the number itself. +For example, the aliquot sum of `15` is `1 + 3 + 5 = 9`. + +## Perfect + +A number is perfect when it equals its aliquot sum. +For example: + +- `6` is a perfect number because `1 + 2 + 3 = 6` +- `28` is a perfect number because `1 + 2 + 4 + 7 + 14 = 28` + +## Abundant + +A number is abundant when it is less than its aliquot sum. +For example: + +- `12` is an abundant number because `1 + 2 + 3 + 4 + 6 = 16` +- `24` is an abundant number because `1 + 2 + 3 + 4 + 6 + 8 + 12 = 36` + +## Deficient + +A number is deficient when it is greater than its aliquot sum. +For example: + +- `8` is a deficient number because `1 + 2 + 4 = 7` +- Prime numbers are deficient + +## Task + +Implement a way to determine whether a given number is [perfect](#perfect). +Depending on your language track, you may also need to implement a way to determine whether a given number is [abundant](#abundant) or [deficient](#deficient). + +[nicomachus]: https://en.wikipedia.org/wiki/Nicomachus +[aliquot-sum]: https://en.wikipedia.org/wiki/Aliquot_sum + +## Exception messages + +Sometimes it is necessary to [raise an exception](https://docs.python.org/3/tutorial/errors.html#raising-exceptions). When you do this, you should always include a **meaningful error message** to indicate what the source of the error is. This makes your code more readable and helps significantly with debugging. For situations where you know that the error source will be a certain type, you can choose to raise one of the [built in error types](https://docs.python.org/3/library/exceptions.html#base-classes), but should still include a meaningful message. + +This particular exercise requires that you use the [raise statement](https://docs.python.org/3/reference/simple_stmts.html#the-raise-statement) to "throw" a `ValueError` if the `classify()` function is passed a number that is not a _positive integer_. The tests will only pass if you both `raise` the `exception` and include a message with it. + +To raise a `ValueError` with a message, write the message as an argument to the `exception` type: + +```python +# if a number to be classified is less than 1. +raise ValueError("Classification is only possible for positive integers.") +``` + +## Source + +### Created by + +- @behrtam + +### Contributed to by + +- @cmccandless +- @Dog +- @emerali +- @ikhadykin +- @N-Parsons +- @olufotebig +- @pheanex +- @saurabhchalke +- @smalley +- @tqa236 + +### Based on + +Taken from Chapter 2 of Functional Thinking by Neal Ford. - https://www.oreilly.com/library/view/functional-thinking/9781449365509/ \ No newline at end of file diff --git a/python/perfect-numbers/__pycache__/perfect_numbers.cpython-313.pyc b/python/perfect-numbers/__pycache__/perfect_numbers.cpython-313.pyc new file mode 100644 index 0000000..43cbf08 Binary files /dev/null and b/python/perfect-numbers/__pycache__/perfect_numbers.cpython-313.pyc differ diff --git a/python/perfect-numbers/__pycache__/perfect_numbers.cpython-314.pyc b/python/perfect-numbers/__pycache__/perfect_numbers.cpython-314.pyc new file mode 100644 index 0000000..f070598 Binary files /dev/null and b/python/perfect-numbers/__pycache__/perfect_numbers.cpython-314.pyc differ diff --git a/python/perfect-numbers/__pycache__/perfect_numbers_test.cpython-313-pytest-8.3.4.pyc b/python/perfect-numbers/__pycache__/perfect_numbers_test.cpython-313-pytest-8.3.4.pyc new file mode 100644 index 0000000..98ad842 Binary files /dev/null and b/python/perfect-numbers/__pycache__/perfect_numbers_test.cpython-313-pytest-8.3.4.pyc differ diff --git a/python/perfect-numbers/__pycache__/perfect_numbers_test.cpython-314-pytest-9.1.0.pyc b/python/perfect-numbers/__pycache__/perfect_numbers_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..de07f9a Binary files /dev/null and b/python/perfect-numbers/__pycache__/perfect_numbers_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/perfect-numbers/perfect_numbers.py b/python/perfect-numbers/perfect_numbers.py new file mode 100644 index 0000000..a405040 --- /dev/null +++ b/python/perfect-numbers/perfect_numbers.py @@ -0,0 +1,20 @@ +def classify(number): + """A perfect number equals the sum of its positive divisors. + + :param number: int a positive integer + :return: str the classification of the input integer + """ + if number <= 0: + raise ValueError( + "Classification is only possible for positive integers.") + aliquot_sum: int = 0 + # find divisors and store them in a list + for divisor in range(1, (number // 2) + 1): + if not number % divisor: + aliquot_sum += divisor + if aliquot_sum == number: + return "perfect" + elif aliquot_sum > number: + return "abundant" + else: + return "deficient" diff --git a/python/perfect-numbers/perfect_numbers_test.py b/python/perfect-numbers/perfect_numbers_test.py new file mode 100644 index 0000000..eef8661 --- /dev/null +++ b/python/perfect-numbers/perfect_numbers_test.py @@ -0,0 +1,68 @@ +# These tests are auto-generated with test data from: +# https://github.com/exercism/problem-specifications/tree/main/exercises/perfect-numbers/canonical-data.json +# File last updated on 2023-07-19 + +import unittest + +from perfect_numbers import ( + classify, +) + + +class PerfectNumbersTest(unittest.TestCase): + def test_smallest_perfect_number_is_classified_correctly(self): + self.assertEqual(classify(6), "perfect") + + def test_medium_perfect_number_is_classified_correctly(self): + self.assertEqual(classify(28), "perfect") + + def test_large_perfect_number_is_classified_correctly(self): + self.assertEqual(classify(33550336), "perfect") + + +class AbundantNumbersTest(unittest.TestCase): + def test_smallest_abundant_number_is_classified_correctly(self): + self.assertEqual(classify(12), "abundant") + + def test_medium_abundant_number_is_classified_correctly(self): + self.assertEqual(classify(30), "abundant") + + def test_large_abundant_number_is_classified_correctly(self): + self.assertEqual(classify(33550335), "abundant") + + +class DeficientNumbersTest(unittest.TestCase): + def test_smallest_prime_deficient_number_is_classified_correctly(self): + self.assertEqual(classify(2), "deficient") + + def test_smallest_non_prime_deficient_number_is_classified_correctly(self): + self.assertEqual(classify(4), "deficient") + + def test_medium_deficient_number_is_classified_correctly(self): + self.assertEqual(classify(32), "deficient") + + def test_large_deficient_number_is_classified_correctly(self): + self.assertEqual(classify(33550337), "deficient") + + def test_edge_case_no_factors_other_than_itself_is_classified_correctly(self): + self.assertEqual(classify(1), "deficient") + + +class InvalidInputsTest(unittest.TestCase): + def test_zero_is_rejected_as_it_is_not_a_positive_integer(self): + with self.assertRaises(ValueError) as err: + classify(0) + self.assertEqual(type(err.exception), ValueError) + self.assertEqual( + err.exception.args[0], + "Classification is only possible for positive integers.", + ) + + def test_negative_integer_is_rejected_as_it_is_not_a_positive_integer(self): + with self.assertRaises(ValueError) as err: + classify(-1) + self.assertEqual(type(err.exception), ValueError) + self.assertEqual( + err.exception.args[0], + "Classification is only possible for positive integers.", + ) diff --git a/python/pig-latin/.exercism/config.json b/python/pig-latin/.exercism/config.json new file mode 100644 index 0000000..6dd8c46 --- /dev/null +++ b/python/pig-latin/.exercism/config.json @@ -0,0 +1,30 @@ +{ + "authors": [ + "behrtam" + ], + "contributors": [ + "akashsara", + "cmccandless", + "Dog", + "ikhadykin", + "N-Parsons", + "pheanex", + "Sukhj1nder", + "tqa236", + "yawpitch" + ], + "files": { + "solution": [ + "pig_latin.py" + ], + "test": [ + "pig_latin_test.py" + ], + "example": [ + ".meta/example.py" + ] + }, + "blurb": "Implement a program that translates from English to Pig Latin.", + "source": "The Pig Latin exercise at Test First Teaching by Ultrasaurus", + "source_url": "https://github.com/ultrasaurus/test-first-teaching/blob/master/learn_ruby/pig_latin/" +} diff --git a/python/pig-latin/.exercism/metadata.json b/python/pig-latin/.exercism/metadata.json new file mode 100644 index 0000000..1409131 --- /dev/null +++ b/python/pig-latin/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"pig-latin","id":"d0a2f3fd1a8f47e1bb428cb46e8f39c7","url":"https://exercism.org/tracks/python/exercises/pig-latin","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/pig-latin/HELP.md b/python/pig-latin/HELP.md new file mode 100644 index 0000000..2972102 --- /dev/null +++ b/python/pig-latin/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +<br> + +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit pig_latin.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/pig-latin/README.md b/python/pig-latin/README.md new file mode 100644 index 0000000..06c2dc2 --- /dev/null +++ b/python/pig-latin/README.md @@ -0,0 +1,82 @@ +# Pig Latin + +Welcome to Pig Latin on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Introduction + +Your parents have challenged you and your sibling to a game of two-on-two basketball. +Confident they'll win, they let you score the first couple of points, but then start taking over the game. +Needing a little boost, you start speaking in [Pig Latin][pig-latin], which is a made-up children's language that's difficult for non-children to understand. +This will give you the edge to prevail over your parents! + +[pig-latin]: https://en.wikipedia.org/wiki/Pig_latin + +## Instructions + +Your task is to translate text from English to Pig Latin. +The translation is defined using four rules, which look at the pattern of vowels and consonants at the beginning of a word. +These rules look at each word's use of vowels and consonants: + +- vowels: the letters `a`, `e`, `i`, `o`, and `u` +- consonants: the other 21 letters of the English alphabet + +## Rule 1 + +If a word begins with a vowel, or starts with `"xr"` or `"yt"`, add an `"ay"` sound to the end of the word. + +For example: + +- `"apple"` -> `"appleay"` (starts with vowel) +- `"xray"` -> `"xrayay"` (starts with `"xr"`) +- `"yttria"` -> `"yttriaay"` (starts with `"yt"`) + +## Rule 2 + +If a word begins with one or more consonants, first move those consonants to the end of the word and then add an `"ay"` sound to the end of the word. + +For example: + +- `"pig"` -> `"igp"` -> `"igpay"` (starts with single consonant) +- `"chair"` -> `"airch"` -> `"airchay"` (starts with multiple consonants) +- `"thrush"` -> `"ushthr"` -> `"ushthray"` (starts with multiple consonants) + +## Rule 3 + +If a word starts with zero or more consonants followed by `"qu"`, first move those consonants (if any) and the `"qu"` part to the end of the word, and then add an `"ay"` sound to the end of the word. + +For example: + +- `"quick"` -> `"ickqu"` -> `"ickquay"` (starts with `"qu"`, no preceding consonants) +- `"square"` -> `"aresqu"` -> `"aresquay"` (starts with one consonant followed by `"qu`") + +## Rule 4 + +If a word starts with one or more consonants followed by `"y"`, first move the consonants preceding the `"y"`to the end of the word, and then add an `"ay"` sound to the end of the word. + +Some examples: + +- `"my"` -> `"ym"` -> `"ymay"` (starts with single consonant followed by `"y"`) +- `"rhythm"` -> `"ythmrh"` -> `"ythmrhay"` (starts with multiple consonants followed by `"y"`) + +## Source + +### Created by + +- @behrtam + +### Contributed to by + +- @akashsara +- @cmccandless +- @Dog +- @ikhadykin +- @N-Parsons +- @pheanex +- @Sukhj1nder +- @tqa236 +- @yawpitch + +### Based on + +The Pig Latin exercise at Test First Teaching by Ultrasaurus - https://github.com/ultrasaurus/test-first-teaching/blob/master/learn_ruby/pig_latin/ \ No newline at end of file diff --git a/python/pig-latin/__pycache__/pig_latin.cpython-313.pyc b/python/pig-latin/__pycache__/pig_latin.cpython-313.pyc new file mode 100644 index 0000000..69f83a9 Binary files /dev/null and b/python/pig-latin/__pycache__/pig_latin.cpython-313.pyc differ diff --git a/python/pig-latin/__pycache__/pig_latin.cpython-314.pyc b/python/pig-latin/__pycache__/pig_latin.cpython-314.pyc new file mode 100644 index 0000000..f664ee3 Binary files /dev/null and b/python/pig-latin/__pycache__/pig_latin.cpython-314.pyc differ diff --git a/python/pig-latin/__pycache__/pig_latin_test.cpython-313-pytest-8.3.4.pyc b/python/pig-latin/__pycache__/pig_latin_test.cpython-313-pytest-8.3.4.pyc new file mode 100644 index 0000000..8b0e850 Binary files /dev/null and b/python/pig-latin/__pycache__/pig_latin_test.cpython-313-pytest-8.3.4.pyc differ diff --git a/python/pig-latin/__pycache__/pig_latin_test.cpython-314-pytest-9.1.0.pyc b/python/pig-latin/__pycache__/pig_latin_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..524e50f Binary files /dev/null and b/python/pig-latin/__pycache__/pig_latin_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/pig-latin/pig_latin.py b/python/pig-latin/pig_latin.py new file mode 100644 index 0000000..439f3ed --- /dev/null +++ b/python/pig-latin/pig_latin.py @@ -0,0 +1,66 @@ +VOWELS: list = [ + "a", + "A", + "e", + "E", + "i", + "I", + "o", + "O", + "u", + "U", +] +# commenting out this list since its not being used +# CONSONANTS: list = [ +# letter for letter in range(ord("A"), ord("Z") + 1) if letter not in VOWELS +# ] + +XR_YT: tuple = ( + "xr", + "Xr", + "XR", + "xR", + "yt", + "Yt", + "YT", + "yT", +) + +# NOTE: this could be easier if used with match pattern (re module) but for +# now lets leave this way. can be used later for refactoring + + +def translate(text): + # list with words translated + pig_latin_text: list = [] + for word in text.split(): + # rule one - starts with vowel or xt/yt + if word.startswith(tuple(VOWELS)) or word.startswith(XR_YT): + pig_latin_text.append(word + "ay") + else: + # rules 2, 3 and 4 starts with consonant, so lets treat them here + consonants_at_start: str = "" # string with grabbed consonants + for index, letter in enumerate(word): + # letter is not a vowel, lets find if rules 3 or 4 applies + if letter not in VOWELS: + # check rule 4 + if letter == "y" and index != 0: + pig_latin_text.append(word[index:] + word[:index] + "ay") + break + # special case of rule 3, when word starts with 'qu' + if word.startswith("qu"): + pig_latin_text.append(word[2:] + word[:2] + "ay") + break + # general case of rule 3, where 'qu' its precessed with only consonants + if word[index + 1 : index + 3] == "qu": + pig_latin_text.append( + word[index + 3 :] + word[: index + 3] + "ay" + ) + break + consonants_at_start += letter + else: + # letter is a vowel, so lets apply rule 2 + pig_latin_text.append(word[index:] + consonants_at_start + "ay") + break + + return " ".join(pig_latin_text) diff --git a/python/pig-latin/pig_latin_test.py b/python/pig-latin/pig_latin_test.py new file mode 100644 index 0000000..1217d68 --- /dev/null +++ b/python/pig-latin/pig_latin_test.py @@ -0,0 +1,80 @@ +# These tests are auto-generated with test data from: +# https://github.com/exercism/problem-specifications/tree/main/exercises/pig-latin/canonical-data.json +# File last updated on 2025-01-10 + +import unittest + +from pig_latin import ( + translate, +) + + +class PigLatinTest(unittest.TestCase): + def test_word_beginning_with_a(self): + self.assertEqual(translate("apple"), "appleay") + + def test_word_beginning_with_e(self): + self.assertEqual(translate("ear"), "earay") + + def test_word_beginning_with_i(self): + self.assertEqual(translate("igloo"), "iglooay") + + def test_word_beginning_with_o(self): + self.assertEqual(translate("object"), "objectay") + + def test_word_beginning_with_u(self): + self.assertEqual(translate("under"), "underay") + + def test_word_beginning_with_a_vowel_and_followed_by_a_qu(self): + self.assertEqual(translate("equal"), "equalay") + + def test_word_beginning_with_p(self): + self.assertEqual(translate("pig"), "igpay") + + def test_word_beginning_with_k(self): + self.assertEqual(translate("koala"), "oalakay") + + def test_word_beginning_with_x(self): + self.assertEqual(translate("xenon"), "enonxay") + + def test_word_beginning_with_q_without_a_following_u(self): + self.assertEqual(translate("qat"), "atqay") + + def test_word_beginning_with_consonant_and_vowel_containing_qu(self): + self.assertEqual(translate("liquid"), "iquidlay") + + def test_word_beginning_with_ch(self): + self.assertEqual(translate("chair"), "airchay") + + def test_word_beginning_with_qu(self): + self.assertEqual(translate("queen"), "eenquay") + + def test_word_beginning_with_qu_and_a_preceding_consonant(self): + self.assertEqual(translate("square"), "aresquay") + + def test_word_beginning_with_th(self): + self.assertEqual(translate("therapy"), "erapythay") + + def test_word_beginning_with_thr(self): + self.assertEqual(translate("thrush"), "ushthray") + + def test_word_beginning_with_sch(self): + self.assertEqual(translate("school"), "oolschay") + + def test_word_beginning_with_yt(self): + self.assertEqual(translate("yttria"), "yttriaay") + + def test_word_beginning_with_xr(self): + self.assertEqual(translate("xray"), "xrayay") + + def test_y_is_treated_like_a_consonant_at_the_beginning_of_a_word(self): + self.assertEqual(translate("yellow"), "ellowyay") + + def test_y_is_treated_like_a_vowel_at_the_end_of_a_consonant_cluster(self): + self.assertEqual(translate("rhythm"), "ythmrhay") + + def test_y_as_second_letter_in_two_letter_word(self): + self.assertEqual(translate("my"), "ymay") + + def test_a_whole_phrase(self): + self.assertEqual(translate("quick fast run"), "ickquay astfay unray") diff --git a/python/plane-tickets/.exercism/config.json b/python/plane-tickets/.exercism/config.json new file mode 100644 index 0000000..1222834 --- /dev/null +++ b/python/plane-tickets/.exercism/config.json @@ -0,0 +1,23 @@ +{ + "authors": [ + "J08K" + ], + "contributors": [ + "BethanyG", + "kytrinyx", + "meatball133" + ], + "files": { + "solution": [ + "generators.py" + ], + "test": [ + "generators_test.py" + ], + "exemplar": [ + ".meta/exemplar.py" + ] + }, + "icon": "new-passport", + "blurb": "Learn about generators by assigning seats to passengers on Anaconda Airlines." +} diff --git a/python/plane-tickets/.exercism/metadata.json b/python/plane-tickets/.exercism/metadata.json new file mode 100644 index 0000000..edf0bde --- /dev/null +++ b/python/plane-tickets/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"plane-tickets","id":"754d7ba9211d45619b389d7835720cbd","url":"https://exercism.org/tracks/python/exercises/plane-tickets","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/plane-tickets/HELP.md b/python/plane-tickets/HELP.md new file mode 100644 index 0000000..3ed49f3 --- /dev/null +++ b/python/plane-tickets/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +<br> + +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit generators.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/plane-tickets/HINTS.md b/python/plane-tickets/HINTS.md new file mode 100644 index 0000000..e00e7f7 --- /dev/null +++ b/python/plane-tickets/HINTS.md @@ -0,0 +1,24 @@ +# Hints + +## 1. Generate seat letters + +- The returned value should be of _type_ `generator`. +- You can have a sequence of letters from `A` to `D` and cycle through them. +- Use `yield` to return the next letter. + +## 2. Generate seats + +- The returned value should be of _type_ `generator`. +- Row `13` should be skipped, so go from `12` to `14`. +- Keep in mind that the returned values should be ordered from low to high. `1A, 1B, 2A, ...` +- Here it might be good to reuse or call functions you have already defined. + +## 3. Assign seats to passengers + +- Make sure your seat numbers do not have any spaces in them. +- Here it might be good to reuse or call functions you have already defined. + +## 4. Ticket codes + +- You can use `len()` to get the length of a string. +- You can use `"<string>" * <int>` to repeat a string. \ No newline at end of file diff --git a/python/plane-tickets/README.md b/python/plane-tickets/README.md new file mode 100644 index 0000000..f793315 --- /dev/null +++ b/python/plane-tickets/README.md @@ -0,0 +1,265 @@ +# Plane Tickets + +Welcome to Plane Tickets on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. +If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :) + +## Introduction + +A `generator` is a function or expression that returns a special type of [iterator][iterator] called [generator iterator][generator-iterator]. +`Generator-iterators` are [lazy][lazy iterator]: they do not store their `values` in memory, but _generate_ their values when needed. + +A generator function looks like any other function, but contains one or more [yield expressions][yield expression]. +Each `yield` will suspend code execution, saving the current execution state (_including all local variables and try-statements_). +When the generator resumes, it picks up state from the suspension - unlike regular functions which reset with every call. + + +## Constructing a generator + +Generators are constructed much like other looping or recursive functions, but require a [`yield` expression](#the-yield-expression), which we will explore in depth a bit later. + +An example is a function that returns the _squares_ from a given list of numbers. +As currently written, all input must be processed before any values can be returned: + +```python +>>> def squares(list_of_numbers): +... squares = [] +... for number in list_of_numbers: +... squares.append(number ** 2) +... return squares +``` + +You can convert that function into a generator like this: + +```python +>>> def squares_generator(list_of_numbers): +... for number in list_of_numbers: +... yield number ** 2 +``` + +The rationale behind this is that you use a generator when you do not need to produce all the values _at once_. +This saves memory and processing power, since only the value you are _currently working on_ is calculated. + + +## Using a generator + +Generators may be used in place of most `iterables` in Python. +This includes _functions_ or _objects_ that require an `iterable`/`iterator` as an argument. + +To use the `squares_generator()` generator: + +```python +>>> squared_numbers = squares_generator([1, 2, 3, 4]) + +>>> for square in squared_numbers: +... print(square) +... +1 +4 +9 +16 +``` + +Values within a `generator` can also be produced/accessed via the `next()` function. +`next()` calls the `__next__()` method of a generator-iterator object, "advancing" or evaluating the code up to its `yield` expression, which then "yields" or returns a value: + +```python +>>> squared_numbers = squares_generator([1, 2]) + +>>> next(squared_numbers) +1 +>>> next(squared_numbers) +4 +``` + +When a `generator-iterator` is fully consumed and has no more values to return, it throws a `StopIteration` error. + +```python +>>> next(squared_numbers) +Traceback (most recent call last): + File "<stdin>", line 1, in <module> +StopIteration +``` + + +~~~~exercism/note + +Generator-iterators are a special sub-set of [iterators][iterator]. +`Iterators` are the mechanism/protocol that enables looping over _iterables_. +Generator-iterators and the iterators returned by common Python [`iterables`][iterables] act very similarly, but there are some important differences to note: + +- They are _[lazily evaluated][lazy evaluation]_; iteration is _one-way_ and there is no "backing up" to a previous value. +- They are _consumed_ by iterating over the returned values; there is no resetting or saving in memory. +- They are not sortable and cannot be reversed. +- They are not sequence types, and _do not_ have `indexes`. + You cannot reference a previous or future value using addition or subtraction and you cannot use bracket (`[]`) notation or slicing. +- They cannot be used with the `len()` function, as they have no length. +- They can be _finite_ or _infinite_ - be careful when collecting all values from an _infinite_ `generator-iterator`! + +[iterator]: https://docs.python.org/3.11/glossary.html#term-iterator +[iterables]: https://wiki.python.org/moin/Iterator +[lazy evaluation]: https://en.wikipedia.org/wiki/Lazy_evaluation +~~~~ + + +## The yield expression + +The [yield expression][yield expression] is very similar to the `return` expression. +_Unlike_ the `return` expression, `yield` gives up values to the caller at a _specific point_, suspending evaluation/return of any additional values until they are requested. +When `yield` is evaluated, it pauses the execution of the enclosing function and returns any values of the function _at that point in time_. +The function then _stays in scope_, and when `__next__()` is called, execution resumes until `yield` is encountered again. + + +~~~~exercism/note +Using `yield` expressions is prohibited outside of functions. +~~~~ + +```python +>>> def infinite_sequence(): +... current_number = 0 +... while True: +... yield current_number +... current_number += 1 + +>>> lets_try = infinite_sequence() +>>> lets_try.__next__() +0 +>>> lets_try.__next__() +1 +``` + + +## Why Create a Generator? + +Generators are useful in a lot of applications. + +When working with a potentially large collection of values, you might not want to put all of them into memory. +A generator can be used to work on larger data piece-by-piece, saving memory and improving performance. + +Generators are also very helpful when a process or calculation is _complex_, _expensive_, or _infinite_: + +```python +>>> def infinite_sequence(): +... current_number = 0 +... while True: +... yield current_number +... current_number += 1 +``` + +Now whenever `__next__()` is called on the `infinite_sequence` object, it will return the _previous number_ + 1. + + +[generator-iterator]: https://docs.python.org/3.11/glossary.html#term-generator-iterator +[iterables]: https://wiki.python.org/moin/Iterator +[iterator]: https://docs.python.org/3.11/glossary.html#term-iterator +[lazy evaluation]: https://en.wikipedia.org/wiki/Lazy_evaluation +[lazy iterator]: https://en.wikipedia.org/wiki/Lazy_evaluation +[yield expression]: https://docs.python.org/3.11/reference/expressions.html#yield-expressions + +## Instructions + +Conda Airlines is the programming-world's biggest airline, with over 10,000 flights a day! + +They are currently assigning all seats to passengers by hand; this will need to be automated. + +They have asked _you_ to create software to automate passenger seat assignments. +They require your software to be memory efficient and performant. + +## 1. Generate seat letters + +Conda wants to generate seat letters for their airplanes. +An airplane is made of rows of seats. +Each row has _4 seats_. +The seats in each row are always named `A`, `B`, `C`, and `D`. +The first seat in the row is `A`, the second seat in the row is `B`, and so on. +After reaching `D`, it should start again with `A`. + +Implement a function `generate_seat_letters(<number>)` that accepts an `int` that holds how many seat letters to be generated. +The function should then return an _iterable_ of seat letters. + +```python +>>> letters = generate_seat_letters(4) +>>> next(letters) +"A" +>>> next(letters) +"B" +``` + +## 2. Generate seats + +Conda wants a system that can generate a given number of seats for their airplanes. +Each airplane has _4 seats_ in each row. +The rows are defined using numbers, starting from `1` and going up. +The seats should be ordered, like: `1A`, `1B`, `1C`, `1D`, `2A`, `2B`, `2C`, `2D`, `3A`, `3B`, `3C`, `3D`, ... + +Here is an example: + +| x | 1 | 2 | +| :---------: | :-: | :-: | +| Row | 5 | 21 | +| Seat letter | A | D | +| Result | 5A | 21D | + +Many airlines do not have _row_ number 13 on their flights, due to superstition amongst passengers. +Conda Airlines also follows this convention, so make sure you _don't_ generate seats for _row_ number 13. + +Implement a function `generate_seats(<number>)` that accepts an `int` that holds how many seats to be generated. +The function should then return an _iterable_ of seats given. + +```python +>>> seats = generate_seats(10) +>>> next(seats) +"1A" +>>> next(seats) +"1B" +``` + +## 3. Assign seats to passengers + +Now that you have a function that generates seats, you can use it to assign seats to passengers. + +Implement a function `assign_seats(<passengers>)` that accepts a `list` of passenger names. +The function should then return a _dictionary_ of `passenger` as _key_, and `seat_number` as _value_. + +```python +>>> passengers = ['Jerimiah', 'Eric', 'Bethany', 'Byte', 'SqueekyBoots', 'Bob'] + +>>> assign_seats(passengers) +{'Jerimiah': '1A', 'Eric': '1B', 'Bethany': '1C', 'Byte': '1D', 'SqueekyBoots': '2A', 'Bob': '2B'} +``` + +## 4. Ticket codes + +Conda Airlines would like to have a unique code for each ticket. +Since they are a big airline, they have a lot of flights. +This means that there are multiple flights with the same seat number. +They want you to create a system that creates a unique ticket that is _12_ characters long string code for identification. + +This code begins with the `assigned_seat` followed by the `flight_id`. +The rest of the code is appended by `0s`. + +Implement a function `generate_codes(<seat_numbers>, <flight_id>)` that accepts a `list` of `seat_numbers` and a `string` with the flight number. +The function should then return a `generator` that yields a `ticket_number`. + +```python +>>> seat_numbers = ['1A', '17D'] +>>> flight_id = 'CO1234' +>>> ticket_ids = generate_codes(seat_numbers, flight_id) + +>>> next(ticket_ids) +'1ACO12340000' +>>> next(ticket_ids) +'17DCO1234000' +``` + +## Source + +### Created by + +- @J08K + +### Contributed to by + +- @BethanyG +- @kytrinyx +- @meatball133 \ No newline at end of file diff --git a/python/plane-tickets/__pycache__/generators.cpython-313.pyc b/python/plane-tickets/__pycache__/generators.cpython-313.pyc new file mode 100644 index 0000000..353c8e9 Binary files /dev/null and b/python/plane-tickets/__pycache__/generators.cpython-313.pyc differ diff --git a/python/plane-tickets/__pycache__/generators.cpython-314.pyc b/python/plane-tickets/__pycache__/generators.cpython-314.pyc new file mode 100644 index 0000000..7a269d0 Binary files /dev/null and b/python/plane-tickets/__pycache__/generators.cpython-314.pyc differ diff --git a/python/plane-tickets/__pycache__/generators_test.cpython-313-pytest-8.3.4.pyc b/python/plane-tickets/__pycache__/generators_test.cpython-313-pytest-8.3.4.pyc new file mode 100644 index 0000000..9c84e2a Binary files /dev/null and b/python/plane-tickets/__pycache__/generators_test.cpython-313-pytest-8.3.4.pyc differ diff --git a/python/plane-tickets/__pycache__/generators_test.cpython-314-pytest-9.1.0.pyc b/python/plane-tickets/__pycache__/generators_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..b0a79d0 Binary files /dev/null and b/python/plane-tickets/__pycache__/generators_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/plane-tickets/generators.py b/python/plane-tickets/generators.py new file mode 100644 index 0000000..597b92c --- /dev/null +++ b/python/plane-tickets/generators.py @@ -0,0 +1,72 @@ +"""Functions to automate Conda airlines ticketing system.""" + + +def generate_seat_letters(number): + """Generate a series of letters for airline seats. + + :param number: int - total number of seat letters to be generated. + :return: generator - generator that yields seat letters. + + Seat letters are generated from A to D. + After D it should start again with A. + + Example: A, B, C, D + + """ + seat_letters: list = ["A", "B", "C", "D"] + for seat_number in range(number): + yield seat_letters[seat_number % len(seat_letters)] + + +def generate_seats(number): + """Generate a series of identifiers for airline seats. + + :param number: int - total number of seats to be generated. + :return: generator - generator that yields seat numbers. + + A seat number consists of the row number and the seat letter. + + There is no row 13. + Each row has 4 seats. + + Seats should be sorted from low to high. + + Example: 3C, 3D, 4A, 4B + + """ + seat_letters = generate_seat_letters(number) + row_number = 1 + for seat_number in range(number): + if not seat_number % 4 and seat_number > 0: + row_number += 1 + if row_number == 13: + row_number += 1 + yield f"{row_number}{next(seat_letters)}" + + +def assign_seats(passengers): + """Assign seats to passengers. + + :param passengers: list[str] - a list of strings containing names of passengers. + :return: dict - with the names of the passengers as keys and seat numbers as values. + + Example output: {"Adele": "1A", "Björk": "1B"} + + """ + seats = generate_seats(len(passengers)) + assign_seats_dict: dict = {} + for passenger in passengers: + assign_seats_dict[passenger] = next(seats) + return assign_seats_dict + + +def generate_codes(seat_numbers, flight_id): + """Generate codes for a ticket. + + :param seat_numbers: list[str] - list of seat numbers. + :param flight_id: str - string containing the flight identifier. + :return: generator - generator that yields 12 character long ticket codes. + + """ + for seat in seat_numbers: + yield f"{seat}{flight_id}".ljust(12, "0") diff --git a/python/plane-tickets/generators_test.py b/python/plane-tickets/generators_test.py new file mode 100644 index 0000000..1596d42 --- /dev/null +++ b/python/plane-tickets/generators_test.py @@ -0,0 +1,140 @@ +import inspect +import unittest +import pytest + +from generators import ( + generate_seat_letters, + generate_seats, + assign_seats, + generate_codes +) + +class PlaneTicketsTest(unittest.TestCase): + @pytest.mark.task(taskno=1) + def test_task1_returns_generator(self): + """Test if generate_seat_letters() returns a generator type.""" + + number = 5 + error_message = (f'Called generate_seat_letters({number}). ' + f'The function returned a {type(generate_seat_letters(number))} type, ' + f"but the tests expected the function to return a <class 'generator'> type.") + + self.assertTrue(inspect.isgenerator(generate_seat_letters(number)), msg=error_message) + + @pytest.mark.task(taskno=1) + def test_generate_seat_letters(self): + test_data = [1, 2, 3, 4, 5] + result_data = [["A"], + ["A", "B"], + ["A", "B", "C"], + ["A", "B", "C", "D"], + ["A", "B", "C", "D", "A"]] + + for variant, (number, expected) in enumerate(zip(test_data, result_data), start=1): + with self.subTest(f"variation #{variant}", number=number, expected=expected): + actual_result = list(generate_seat_letters(number)) + error_message = (f'Called generate_seat_letters({number}). ' + f'The function returned {actual_result}, but the tests ' + f'expected {expected} when generating {number} seat(s).') + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=2) + def test_task2_returns_generator(self): + """Test if generate_seats() returns a generator type.""" + + number = 7 + error_message = (f'Called generate_seats({number}). ' + f'The function returned a {type(generate_seats(number))} type, ' + f"but the tests expected the function to return a <class 'generator'> type.") + + self.assertTrue(inspect.isgenerator(generate_seats(number)), msg=error_message) + + @pytest.mark.task(taskno=2) + def test_generate_seats(self): + test_data = [1, 2, 3, 4, 5] + result_data = [["1A"], + ["1A", "1B"], + ["1A", "1B", "1C"], + ["1A", "1B", "1C", "1D"], + ["1A", "1B", "1C", "1D", "2A"]] + + for variant, (number, expected) in enumerate(zip(test_data, result_data), start=1): + with self.subTest(f"variation #{variant}", number=number, expected=expected): + actual_result = list(generate_seats(number)) + error_message = (f'Called generate_seats({number}). ' + f'The function returned {actual_result}, but the tests ' + f'expected {expected} when generating {number} seat(s).') + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=2) + def test_generate_seats_skips_row_13(self): + test_data = [14 * 4] + result_data = [["1A", "1B", "1C", "1D", "2A", "2B", "2C", "2D", + "3A", "3B", "3C", "3D", "4A", "4B", "4C", "4D", + "5A", "5B", "5C", "5D", "6A", "6B", "6C", "6D", + "7A", "7B", "7C", "7D", "8A", "8B", "8C", "8D", + "9A", "9B", "9C", "9D", "10A", "10B", "10C", "10D", + "11A", "11B", "11C", "11D", "12A", "12B", "12C", "12D", + "14A", "14B", "14C", "14D", "15A", "15B", "15C", "15D"]] + + for variant, (number, expected) in enumerate(zip(test_data, result_data), start=1): + with self.subTest(f"variation #{variant}", number=number, expected=expected): + actual_result = list(generate_seats(number)) + error_message = (f'Called generate_seats({number}). ' + f'The function returned {actual_result}, but the tests ' + f'expected: {expected}, when generating {number} seat(s).') + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=3) + def test_assign_seats(self): + test_data = [["Passenger1", "Passenger2", "Passenger3", "Passenger4", "Passenger5"], + ["TicketNo=5644", "TicketNo=2273", "TicketNo=493", "TicketNo=5411", "TicketNo=824"]] + result_data = [{"Passenger1": "1A", "Passenger2": "1B", + "Passenger3": "1C", "Passenger4": "1D", "Passenger5": "2A"}, + {"TicketNo=5644": "1A", "TicketNo=2273": "1B", + "TicketNo=493": "1C", "TicketNo=5411": "1D", "TicketNo=824": "2A"}] + + for variant, (passengers, expected) in enumerate(zip(test_data, result_data), start=1): + with self.subTest(f"variation #{variant}", passengers=passengers, expected=expected): + actual_result = assign_seats(passengers) + error_message = (f'Called assign_seats({passengers}). ' + f'The function returned {actual_result}, but the tests ' + f'expected {expected}, when assigning seats.') + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=4) + def test_task4_returns_generator(self): + """Test if generate_codes() returns a generator type.""" + + seat_numbers, flight_id = "11B", "HA80085" + error_message = (f'Called generate_codes({seat_numbers}, {flight_id}). ' + f'The function returned a {type(generate_codes(seat_numbers, flight_id))} type, ' + f"but the tests expected the function to return a <class 'generator'> type.") + + self.assertTrue(inspect.isgenerator(generate_codes(seat_numbers, flight_id)), msg=error_message) + + + @pytest.mark.task(taskno=4) + def test_generate_codes(self): + test_data = [(["12A", "38B", "69C", "102B"],"KL1022"), + (["22C", "88B", "33A", "44B"], "DL1002")] + result_data = [['12AKL1022000', '38BKL1022000', '69CKL1022000', '102BKL102200'], + ['22CDL1002000', '88BDL1002000', '33ADL1002000', '44BDL1002000']] + + for variant, ((seat_numbers, flight_id), expected) in enumerate(zip(test_data, result_data), start=1): + with self.subTest(f"variation #{variant}", seat_numbbers=seat_numbers, + flight_id=flight_id, expected=expected): + + actual_result = list(generate_codes(seat_numbers, flight_id)) + error_message = (f'Called generate_codes({seat_numbers}, {flight_id}). ' + f'The function returned {actual_result}, but the tests ' + f'expected {expected} when generating ticket numbers.') + + # Note: DO NOT call the function here again, in case the student is using list.pop() + # to process the input. If another call is done with that condition, + # the test will fail with a terrible error message. + self.assertEqual(actual_result, expected, msg=error_message) diff --git a/python/prime-factors/.exercism/config.json b/python/prime-factors/.exercism/config.json new file mode 100644 index 0000000..f50d3fc --- /dev/null +++ b/python/prime-factors/.exercism/config.json @@ -0,0 +1,32 @@ +{ + "authors": [], + "contributors": [ + "behrtam", + "BethanyG", + "cmccandless", + "crsmi", + "Dog", + "ikhadykin", + "kytrinyx", + "lowks", + "N-Parsons", + "pheanex", + "sjakobi", + "subkrish", + "tqa236" + ], + "files": { + "solution": [ + "prime_factors.py" + ], + "test": [ + "prime_factors_test.py" + ], + "example": [ + ".meta/example.py" + ] + }, + "blurb": "Compute the prime factors of a given natural number.", + "source": "The Prime Factors Kata by Uncle Bob", + "source_url": "https://web.archive.org/web/20221026171801/http://butunclebob.com/ArticleS.UncleBob.ThePrimeFactorsKata" +} diff --git a/python/prime-factors/.exercism/metadata.json b/python/prime-factors/.exercism/metadata.json new file mode 100644 index 0000000..1bfa5b6 --- /dev/null +++ b/python/prime-factors/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"prime-factors","id":"2bcba47200a345c1839382ac84cc4b11","url":"https://exercism.org/tracks/python/exercises/prime-factors","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/prime-factors/HELP.md b/python/prime-factors/HELP.md new file mode 100644 index 0000000..6f7e351 --- /dev/null +++ b/python/prime-factors/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Correr os testes + +Usamos o [pytest][pytest: Getting Started Guide] como executor de testes do nosso site. +Vais precisar de instalar o `pytest` na tua máquina de desenvolvimento se quiseres correr os testes do percurso Python localmente. +Também vais precisar de instalar os seguintes plugins do `pytest`: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Encontras informação mais detalhada no [guia de testes de Python][Python track tests page] do nosso site. + + +### Correr os testes + +Para correres os testes incluídos, navega até à pasta onde o exercício está guardado usando o `cd` no teu terminal (_substitui `<exercise-folder-location>` abaixo pelo teu caminho_). +Os ficheiros de teste terminam habitualmente em `_test.py` e são os mesmos testes que correm no site quando uma solução é submetida. + +Linux/MacOS +```bash +$ cd <path/to/exercise-folder-location> +``` + +Windows +```powershell +PS C:\Users\foobar> cd <path\to\exercise-folder-location> +``` + +<br> + +De seguida, corre o comando `pytest` no teu terminal, substituindo `<exercise_test.py>` pelo nome do ficheiro de teste: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task <exercise_test.py> +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task <exercise_test.py> +==================== 7 passed in 0.08s ==================== +``` + + +### Opções comuns +- `-o` : substitui o `pytest.ini` predefinido (_podes usar esta opção para evitar avisos de marcadores_) +- `-v` : ativa a saída detalhada. +- `-x` : para de correr os testes na primeira falha. +- `--ff` : corre as falhas do teste anterior antes de correr os outros casos de teste. + +Para opções adicionais, usa `python3 -m pytest -h` ou `py -m pytest -h`. + + +### Corrigir avisos + +Se não usares `pytest -o markers=task` ao invocar o `pytest`, podes receber um `PytestUnknownMarkWarning` nos testes que usam a nossa nova sintaxe: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +Para evitares escrever `pytest -o markers=task` em todos os testes que corres, podes usar um ficheiro de configuração `pytest.ini`. +Criámos um que podes descarregar a partir do nível de topo do diretório do percurso Python: [pytest.ini][pytest.ini]. + +Também podes criar o teu próprio ficheiro `pytest.ini` com o seguinte conteúdo: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Colocar o ficheiro `pytest.ini` no diretório _root_ ou _working_ dos teus exercícios do percurso Python regista os marcadores e faz parar os avisos. +Encontras mais informação sobre os marcadores do pytest na documentação do `pytest` sobre [marcar funções de teste][pytest: marking test functions with attributes] e na documentação do `pytest` sobre [trabalhar com marcadores personalizados][pytest: working with custom markers]. + +Encontras informação sobre como personalizar as configurações do pytest na documentação do `pytest` sobre [formatos de ficheiros de configuração][pytest: configuration file formats]. + + +### Estender o teu IDE ou editor de código + +Muitos IDEs e editores de código têm suporte integrado para usar o `pytest` e outras ferramentas de qualidade de código. +Podes encontrar algumas opções da comunidade na nossa [página de ferramentas do percurso Python][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submeter a tua solução + +Podes submeter a tua solução com o comando `exercism submit prime_factors.py`. +Este comando envia a tua solução para o site do Exercism e imprime o URL da página da solução. + +É possível submeter uma solução incompleta, o que te permite: + +- Ver como outras pessoas resolveram o exercício +- Pedir ajuda a um mentor + +## Precisas de ajuda? + +Se quiseres ajuda para resolver o exercício, consulta as seguintes páginas: + +- A [documentação do percurso Python](https://exercism.org/docs/tracks/python) +- A [categoria de programação do percurso Python no fórum](https://forum.exercism.org/c/programming/python) +- A [categoria de programação do Exercism no fórum](https://forum.exercism.org/c/programming/5) +- As [Perguntas Frequentes](https://exercism.org/docs/using/faqs) + +Se esses recursos não forem suficientes, podes submeter a tua solução (incompleta) para pedir mentoria. + +Abaixo encontras alguns recursos para obter ajuda, caso tenhas problemas: + +- [A PSF](https://www.python.org) aloja as transferências do Python, a documentação e recursos da comunidade. +- Os [Fóruns da Comunidade Python](https://discuss.python.org/) servem para obter ajuda, discutir PEPs, falar com os principais contribuidores do Python e muito mais. +- [A Comunidade do Exercism no Discord](https://exercism.org/r/discord) +- [Os Fóruns de Discussão da Comunidade do Exercism](https://forum.exercsim.org) +- A [Comunidade Python no Discord](https://pythondiscord.com/) é uma comunidade muito prestável e ativa. +- O [/r/learnpython/](https://www.reddit.com/r/learnpython/) é um subreddit pensado para quem está a aprender Python. +- O [#python no Libera.chat](https://www.python.org/community/irc/) é o sítio onde os programadores responsáveis pela linguagem se juntam e põem o trabalho em dia. +- Os [Fóruns da Comunidade Free Code Camp](https://forum.freecodecamp.org/) +- O [Pythontutor](http://pythontutor.com/) para percorrer pequenos excertos de código visualmente. + +Além disso, o [StackOverflow](http://stackoverflow.com/questions/tagged/python) é um bom sítio para procurar o teu problema ou a tua dúvida e ver se já foi respondida. +Se não foi, podes sempre [perguntar](https://stackoverflow.com/help/how-to-ask) ou [responder](https://stackoverflow.com/help/how-to-answer) à pergunta de outra pessoa. \ No newline at end of file diff --git a/python/prime-factors/README.md b/python/prime-factors/README.md new file mode 100644 index 0000000..028eb58 --- /dev/null +++ b/python/prime-factors/README.md @@ -0,0 +1,63 @@ +# Fatores primos + +Bem-vindo ao Fatores primos no percurso Python do Exercism. +Se precisares de ajuda para correr os testes ou para submeter o teu código, consulta o `HELP.md`. + +## Instructions + +Calcula os fatores primos de um número natural. + +Um número primo só é divisível por si próprio e por 1. + +Repara que 1 não é um número primo. + +## Exemplo + +Quais são os fatores primos de 60? + +- O nosso primeiro divisor é o 2. + O 2 divide 60, dando 30. +- O 2 divide 30, dando 15. + - O 2 não divide 15 de forma exata. + Por isso, vamos passar ao nosso próximo divisor, o 3. +- O 3 divide 15 de forma exata, dando 5. + - O 3 não divide 5 de forma exata. + O próximo fator possível é o 4. + - O 4 não divide 5 de forma exata. + O próximo fator possível é o 5. +- O 5 divide 5 de forma exata. +- Resta-nos apenas o 1, por isso, agora, terminámos. + +Os divisores que resultaram neste cálculo representam a lista dos fatores primos de 60: 2, 2, 3 e 5. + +Podes verificar isto por ti: + +```text +2 * 2 * 3 * 5 += 4 * 15 += 60 +``` + +Sucesso! + +## Source + +### Contributed to by + +- @behrtam +- @BethanyG +- @cmccandless +- @crsmi +- @Dog +- @ikhadykin +- @kytrinyx +- @lowks +- @N-Parsons +- @pheanex +- @sjakobi +- @subkrish +- @tqa236 + +### Based on + +The Prime Factors Kata by Uncle Bob - https://web.archive.org/web/20221026171801/http://butunclebob.com/ArticleS.UncleBob.ThePrimeFactorsKata \ No newline at end of file diff --git a/python/prime-factors/__pycache__/prime_factors.cpython-314.pyc b/python/prime-factors/__pycache__/prime_factors.cpython-314.pyc new file mode 100644 index 0000000..cdb9ad6 Binary files /dev/null and b/python/prime-factors/__pycache__/prime_factors.cpython-314.pyc differ diff --git a/python/prime-factors/__pycache__/prime_factors_test.cpython-314-pytest-9.1.0.pyc b/python/prime-factors/__pycache__/prime_factors_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..f2348d3 Binary files /dev/null and b/python/prime-factors/__pycache__/prime_factors_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/prime-factors/prime_factors.py b/python/prime-factors/prime_factors.py new file mode 100644 index 0000000..9cb1108 --- /dev/null +++ b/python/prime-factors/prime_factors.py @@ -0,0 +1,10 @@ +def factors(value): + prime_factors: list[int] = [] + factor: int = 2 + while value > 1: + if value % factor == 0: + prime_factors.append(factor) + value //= factor + else: + factor += 1 + return prime_factors diff --git a/python/prime-factors/prime_factors_test.py b/python/prime-factors/prime_factors_test.py new file mode 100644 index 0000000..a1d5d4d --- /dev/null +++ b/python/prime-factors/prime_factors_test.py @@ -0,0 +1,48 @@ +# These tests are auto-generated with test data from: +# https://github.com/exercism/problem-specifications/tree/main/exercises/prime-factors/canonical-data.json +# File last updated on 2026-02-19 + +import unittest + +from prime_factors import ( + factors, +) + + +class PrimeFactorsTest(unittest.TestCase): + + def test_no_factors(self): + self.assertEqual(factors(1), []) + + def test_prime_number(self): + self.assertEqual(factors(2), [2]) + + def test_another_prime_number(self): + self.assertEqual(factors(3), [3]) + + def test_square_of_a_prime(self): + self.assertEqual(factors(9), [3, 3]) + + def test_product_of_first_prime(self): + self.assertEqual(factors(4), [2, 2]) + + def test_cube_of_a_prime(self): + self.assertEqual(factors(8), [2, 2, 2]) + + def test_product_of_second_prime(self): + self.assertEqual(factors(27), [3, 3, 3]) + + def test_product_of_third_prime(self): + self.assertEqual(factors(625), [5, 5, 5, 5]) + + def test_product_of_first_and_second_prime(self): + self.assertEqual(factors(6), [2, 3]) + + def test_product_of_primes_and_non_primes(self): + self.assertEqual(factors(12), [2, 2, 3]) + + def test_product_of_primes(self): + self.assertEqual(factors(901255), [5, 17, 23, 461]) + + def test_factors_include_a_large_prime(self): + self.assertEqual(factors(93819012551), [11, 9539, 894119]) diff --git a/python/protein-translation/.exercism/config.json b/python/protein-translation/.exercism/config.json new file mode 100644 index 0000000..3a2569b --- /dev/null +++ b/python/protein-translation/.exercism/config.json @@ -0,0 +1,30 @@ +{ + "authors": [ + "cptjackson" + ], + "contributors": [ + "behrtam", + "cmccandless", + "Dog", + "ikhadykin", + "N-Parsons", + "nmbrgts", + "sjwarner-bp", + "thomasjpfan", + "tqa236", + "yawpitch" + ], + "files": { + "solution": [ + "protein_translation.py" + ], + "test": [ + "protein_translation_test.py" + ], + "example": [ + ".meta/example.py" + ] + }, + "blurb": "Translate RNA sequences into proteins.", + "source": "Tyler Long" +} diff --git a/python/protein-translation/.exercism/metadata.json b/python/protein-translation/.exercism/metadata.json new file mode 100644 index 0000000..180071e --- /dev/null +++ b/python/protein-translation/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"protein-translation","id":"8026e7b82d9e4f3cb2dea9fa4b08f665","url":"https://exercism.org/tracks/python/exercises/protein-translation","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/protein-translation/HELP.md b/python/protein-translation/HELP.md new file mode 100644 index 0000000..e4f20b8 --- /dev/null +++ b/python/protein-translation/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Correr os testes + +Usamos o [pytest][pytest: Getting Started Guide] como executor de testes do nosso site. +Vais precisar de instalar o `pytest` na tua máquina de desenvolvimento se quiseres correr os testes do percurso Python localmente. +Também vais precisar de instalar os seguintes plugins do `pytest`: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Encontras informação mais detalhada no [guia de testes de Python][Python track tests page] do nosso site. + + +### Correr os testes + +Para correres os testes incluídos, navega até à pasta onde o exercício está guardado usando o `cd` no teu terminal (_substitui `<exercise-folder-location>` abaixo pelo teu caminho_). +Os ficheiros de teste terminam habitualmente em `_test.py` e são os mesmos testes que correm no site quando uma solução é submetida. + +Linux/MacOS +```bash +$ cd <path/to/exercise-folder-location> +``` + +Windows +```powershell +PS C:\Users\foobar> cd <path\to\exercise-folder-location> +``` + +<br> + +De seguida, corre o comando `pytest` no teu terminal, substituindo `<exercise_test.py>` pelo nome do ficheiro de teste: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task <exercise_test.py> +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task <exercise_test.py> +==================== 7 passed in 0.08s ==================== +``` + + +### Opções comuns +- `-o` : substitui o `pytest.ini` predefinido (_podes usar esta opção para evitar avisos de marcadores_) +- `-v` : ativa a saída detalhada. +- `-x` : para de correr os testes na primeira falha. +- `--ff` : corre as falhas do teste anterior antes de correr os outros casos de teste. + +Para opções adicionais, usa `python3 -m pytest -h` ou `py -m pytest -h`. + + +### Corrigir avisos + +Se não usares `pytest -o markers=task` ao invocar o `pytest`, podes receber um `PytestUnknownMarkWarning` nos testes que usam a nossa nova sintaxe: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +Para evitares escrever `pytest -o markers=task` em todos os testes que corres, podes usar um ficheiro de configuração `pytest.ini`. +Criámos um que podes descarregar a partir do nível de topo do diretório do percurso Python: [pytest.ini][pytest.ini]. + +Também podes criar o teu próprio ficheiro `pytest.ini` com o seguinte conteúdo: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Colocar o ficheiro `pytest.ini` no diretório _root_ ou _working_ dos teus exercícios do percurso Python regista os marcadores e faz parar os avisos. +Encontras mais informação sobre os marcadores do pytest na documentação do `pytest` sobre [marcar funções de teste][pytest: marking test functions with attributes] e na documentação do `pytest` sobre [trabalhar com marcadores personalizados][pytest: working with custom markers]. + +Encontras informação sobre como personalizar as configurações do pytest na documentação do `pytest` sobre [formatos de ficheiros de configuração][pytest: configuration file formats]. + + +### Estender o teu IDE ou editor de código + +Muitos IDEs e editores de código têm suporte integrado para usar o `pytest` e outras ferramentas de qualidade de código. +Podes encontrar algumas opções da comunidade na nossa [página de ferramentas do percurso Python][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submeter a tua solução + +Podes submeter a tua solução com o comando `exercism submit protein_translation.py`. +Este comando envia a tua solução para o site do Exercism e imprime o URL da página da solução. + +É possível submeter uma solução incompleta, o que te permite: + +- Ver como outras pessoas resolveram o exercício +- Pedir ajuda a um mentor + +## Precisas de ajuda? + +Se quiseres ajuda para resolver o exercício, consulta as seguintes páginas: + +- A [documentação do percurso Python](https://exercism.org/docs/tracks/python) +- A [categoria de programação do percurso Python no fórum](https://forum.exercism.org/c/programming/python) +- A [categoria de programação do Exercism no fórum](https://forum.exercism.org/c/programming/5) +- As [Perguntas Frequentes](https://exercism.org/docs/using/faqs) + +Se esses recursos não forem suficientes, podes submeter a tua solução (incompleta) para pedir mentoria. + +Abaixo encontras alguns recursos para obter ajuda, caso tenhas problemas: + +- [A PSF](https://www.python.org) aloja as transferências do Python, a documentação e recursos da comunidade. +- Os [Fóruns da Comunidade Python](https://discuss.python.org/) servem para obter ajuda, discutir PEPs, falar com os principais contribuidores do Python e muito mais. +- [A Comunidade do Exercism no Discord](https://exercism.org/r/discord) +- [Os Fóruns de Discussão da Comunidade do Exercism](https://forum.exercsim.org) +- A [Comunidade Python no Discord](https://pythondiscord.com/) é uma comunidade muito prestável e ativa. +- O [/r/learnpython/](https://www.reddit.com/r/learnpython/) é um subreddit pensado para quem está a aprender Python. +- O [#python no Libera.chat](https://www.python.org/community/irc/) é o sítio onde os programadores responsáveis pela linguagem se juntam e põem o trabalho em dia. +- Os [Fóruns da Comunidade Free Code Camp](https://forum.freecodecamp.org/) +- O [Pythontutor](http://pythontutor.com/) para percorrer pequenos excertos de código visualmente. + +Além disso, o [StackOverflow](http://stackoverflow.com/questions/tagged/python) é um bom sítio para procurar o teu problema ou a tua dúvida e ver se já foi respondida. +Se não foi, podes sempre [perguntar](https://stackoverflow.com/help/how-to-ask) ou [responder](https://stackoverflow.com/help/how-to-answer) à pergunta de outra pessoa. \ No newline at end of file diff --git a/python/protein-translation/README.md b/python/protein-translation/README.md new file mode 100644 index 0000000..225911d --- /dev/null +++ b/python/protein-translation/README.md @@ -0,0 +1,66 @@ +# Tradução de proteínas + +Bem-vindo ao Tradução de proteínas no percurso Python do Exercism. +Se precisares de ajuda para correr os testes ou para submeter o teu código, consulta o `HELP.md`. + +## Instructions + +A tua tarefa é traduzir sequências de ARN em proteínas. + +As cadeias de ARN são constituídas por sequências de três nucleótidos chamadas **codões**. +Cada codão traduz-se num **aminoácido**. +Quando se unem, esses aminoácidos formam uma proteína. + +No mundo real existem 64 codões, que por sua vez correspondem a 20 aminoácidos. +No entanto, neste exercício só vais usar alguns dos 64 possíveis. +Estão listados a seguir: + +| Codão | Aminoácido | +| ------------------ | ------------- | +| AUG | Methionine | +| UUU, UUC | Phenylalanine | +| UUA, UUG | Leucine | +| UCU, UCC, UCA, UCG | Serine | +| UAU, UAC | Tyrosine | +| UGU, UGC | Cysteine | +| UGG | Tryptophan | +| UAA, UAG, UGA | STOP | + +Por exemplo, a string de ARN “AUGUUUUCU” tem três codões: “AUG”, “UUU” e “UCU”. +Estes correspondem a Methionine, Phenylalanine e Serine. + +## Codões “STOP” + +Repara que, na tabela acima, há três **codões “STOP”**. +Se encontrares algum destes codões, ignora o resto da sequência: a proteína está completa. + +Por exemplo, “AUGUUUUCUUAAAUG” contém um codão STOP (“UAA”). +Assim que chegamos a esse ponto, deixamos de processar. +Por isso, só consideramos a parte anterior a ele (ou seja, “AUGUUUUCU”), e não os codões que vêm depois (ou seja, “AUG”). + +Sabe mais sobre [tradução de proteínas na Wikipédia][protein-translation]. + +[protein-translation]: https://en.wikipedia.org/wiki/Translation_(biology) + +## Source + +### Created by + +- @cptjackson + +### Contributed to by + +- @behrtam +- @cmccandless +- @Dog +- @ikhadykin +- @N-Parsons +- @nmbrgts +- @sjwarner-bp +- @thomasjpfan +- @tqa236 +- @yawpitch + +### Based on + +Tyler Long \ No newline at end of file diff --git a/python/protein-translation/__pycache__/protein_translation.cpython-314.pyc b/python/protein-translation/__pycache__/protein_translation.cpython-314.pyc new file mode 100644 index 0000000..e990ad2 Binary files /dev/null and b/python/protein-translation/__pycache__/protein_translation.cpython-314.pyc differ diff --git a/python/protein-translation/__pycache__/protein_translation_test.cpython-314-pytest-9.1.0.pyc b/python/protein-translation/__pycache__/protein_translation_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..916f70d Binary files /dev/null and b/python/protein-translation/__pycache__/protein_translation_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/protein-translation/protein_translation.py b/python/protein-translation/protein_translation.py new file mode 100644 index 0000000..21e8e23 --- /dev/null +++ b/python/protein-translation/protein_translation.py @@ -0,0 +1,31 @@ +codon_to_protein: dict[str, str] = { + "AUG": "Methionine", + "UUU": "Phenylalanine", + "UUC": "Phenylalanine", + "UUA": "Leucine", + "UUG": "Leucine", + "UCU": "Serine", + "UCC": "Serine", + "UCA": "Serine", + "UCG": "Serine", + "UAU": "Tyrosine", + "UAC": "Tyrosine", + "UGU": "Cysteine", + "UGC": "Cysteine", + "UGG": "Tryptophan", +} + +stop_codons: list[str] = ["UAA", "UAG", "UGA"] + + +def proteins(strand): + protein: list[str] = [] + codon: str = "" + for nucleotide in strand: + codon += nucleotide + if len(codon) == 3: + if codon in stop_codons: + break + protein.append(codon_to_protein[codon]) + codon = "" + return protein diff --git a/python/protein-translation/protein_translation_test.py b/python/protein-translation/protein_translation_test.py new file mode 100644 index 0000000..03a20fa --- /dev/null +++ b/python/protein-translation/protein_translation_test.py @@ -0,0 +1,141 @@ +# These tests are auto-generated with test data from: +# https://github.com/exercism/problem-specifications/tree/main/exercises/protein-translation/canonical-data.json +# File last updated on 2024-07-08 + +import unittest + +from protein_translation import ( + proteins, +) + + +class ProteinTranslationTest(unittest.TestCase): + def test_methionine_rna_sequence(self): + value = "AUG" + expected = ["Methionine"] + self.assertEqual(proteins(value), expected) + + def test_phenylalanine_rna_sequence_1(self): + value = "UUU" + expected = ["Phenylalanine"] + self.assertEqual(proteins(value), expected) + + def test_phenylalanine_rna_sequence_2(self): + value = "UUC" + expected = ["Phenylalanine"] + self.assertEqual(proteins(value), expected) + + def test_leucine_rna_sequence_1(self): + value = "UUA" + expected = ["Leucine"] + self.assertEqual(proteins(value), expected) + + def test_leucine_rna_sequence_2(self): + value = "UUG" + expected = ["Leucine"] + self.assertEqual(proteins(value), expected) + + def test_serine_rna_sequence_1(self): + value = "UCU" + expected = ["Serine"] + self.assertEqual(proteins(value), expected) + + def test_serine_rna_sequence_2(self): + value = "UCC" + expected = ["Serine"] + self.assertEqual(proteins(value), expected) + + def test_serine_rna_sequence_3(self): + value = "UCA" + expected = ["Serine"] + self.assertEqual(proteins(value), expected) + + def test_serine_rna_sequence_4(self): + value = "UCG" + expected = ["Serine"] + self.assertEqual(proteins(value), expected) + + def test_tyrosine_rna_sequence_1(self): + value = "UAU" + expected = ["Tyrosine"] + self.assertEqual(proteins(value), expected) + + def test_tyrosine_rna_sequence_2(self): + value = "UAC" + expected = ["Tyrosine"] + self.assertEqual(proteins(value), expected) + + def test_cysteine_rna_sequence_1(self): + value = "UGU" + expected = ["Cysteine"] + self.assertEqual(proteins(value), expected) + + def test_cysteine_rna_sequence_2(self): + value = "UGC" + expected = ["Cysteine"] + self.assertEqual(proteins(value), expected) + + def test_tryptophan_rna_sequence(self): + value = "UGG" + expected = ["Tryptophan"] + self.assertEqual(proteins(value), expected) + + def test_stop_codon_rna_sequence_1(self): + value = "UAA" + expected = [] + self.assertEqual(proteins(value), expected) + + def test_stop_codon_rna_sequence_2(self): + value = "UAG" + expected = [] + self.assertEqual(proteins(value), expected) + + def test_stop_codon_rna_sequence_3(self): + value = "UGA" + expected = [] + self.assertEqual(proteins(value), expected) + + def test_sequence_of_two_protein_codons_translates_into_proteins(self): + value = "UUUUUU" + expected = ["Phenylalanine", "Phenylalanine"] + self.assertEqual(proteins(value), expected) + + def test_sequence_of_two_different_protein_codons_translates_into_proteins(self): + value = "UUAUUG" + expected = ["Leucine", "Leucine"] + self.assertEqual(proteins(value), expected) + + def test_translate_rna_strand_into_correct_protein_list(self): + value = "AUGUUUUGG" + expected = ["Methionine", "Phenylalanine", "Tryptophan"] + self.assertEqual(proteins(value), expected) + + def test_translation_stops_if_stop_codon_at_beginning_of_sequence(self): + value = "UAGUGG" + expected = [] + self.assertEqual(proteins(value), expected) + + def test_translation_stops_if_stop_codon_at_end_of_two_codon_sequence(self): + value = "UGGUAG" + expected = ["Tryptophan"] + self.assertEqual(proteins(value), expected) + + def test_translation_stops_if_stop_codon_at_end_of_three_codon_sequence(self): + value = "AUGUUUUAA" + expected = ["Methionine", "Phenylalanine"] + self.assertEqual(proteins(value), expected) + + def test_translation_stops_if_stop_codon_in_middle_of_three_codon_sequence(self): + value = "UGGUAGUGG" + expected = ["Tryptophan"] + self.assertEqual(proteins(value), expected) + + def test_translation_stops_if_stop_codon_in_middle_of_six_codon_sequence(self): + value = "UGGUGUUAUUAAUGGUUU" + expected = ["Tryptophan", "Cysteine", "Tyrosine"] + self.assertEqual(proteins(value), expected) + + def test_sequence_of_two_non_stop_codons_does_not_translate_to_a_stop_codon(self): + value = "AUGAUG" + expected = ["Methionine", "Methionine"] + self.assertEqual(proteins(value), expected) diff --git a/python/raindrops/.exercism/config.json b/python/raindrops/.exercism/config.json new file mode 100644 index 0000000..70763b8 --- /dev/null +++ b/python/raindrops/.exercism/config.json @@ -0,0 +1,32 @@ +{ + "authors": [], + "contributors": [ + "behrtam", + "BethanyG", + "bsoyka", + "cmccandless", + "Dog", + "ikhadykin", + "kytrinyx", + "lowks", + "N-Parsons", + "pheanex", + "sjakobi", + "tqa236", + "yawpitch" + ], + "files": { + "solution": [ + "raindrops.py" + ], + "test": [ + "raindrops_test.py" + ], + "example": [ + ".meta/example.py" + ] + }, + "blurb": "Convert a number into its corresponding raindrop sounds - Pling, Plang and Plong.", + "source": "A variation on FizzBuzz, a famous technical interview question that is intended to weed out potential candidates. That question is itself derived from Fizz Buzz, a popular children's game for teaching division.", + "source_url": "https://en.wikipedia.org/wiki/Fizz_buzz" +} diff --git a/python/raindrops/.exercism/metadata.json b/python/raindrops/.exercism/metadata.json new file mode 100644 index 0000000..54f6a4e --- /dev/null +++ b/python/raindrops/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"raindrops","id":"637f06e3ae4e46dd8133346315df02d4","url":"https://exercism.org/tracks/python/exercises/raindrops","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/raindrops/HELP.md b/python/raindrops/HELP.md new file mode 100644 index 0000000..8739752 --- /dev/null +++ b/python/raindrops/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +<br> + +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit raindrops.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/raindrops/README.md b/python/raindrops/README.md new file mode 100644 index 0000000..e0b0ddd --- /dev/null +++ b/python/raindrops/README.md @@ -0,0 +1,75 @@ +# Raindrops + +Welcome to Raindrops on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Introduction + +Raindrops is a slightly more complex version of the FizzBuzz challenge, a classic interview question. + +## Instructions + +Your task is to convert a number into its corresponding raindrop sounds. + +If a given number: + +- is divisible by 3, add "Pling" to the result. +- is divisible by 5, add "Plang" to the result. +- is divisible by 7, add "Plong" to the result. +- **is not** divisible by 3, 5, or 7, the result should be the number as a string. + +## Examples + +- 28 is divisible by 7, but not 3 or 5, so the result would be `"Plong"`. +- 30 is divisible by 3 and 5, but not 7, so the result would be `"PlingPlang"`. +- 34 is not divisible by 3, 5, or 7, so the result would be `"34"`. + +~~~~exercism/note +A common way to test if one number is evenly divisible by another is to compare the [remainder][remainder] or [modulus][modulo] to zero. +Most languages provide operators or functions for one (or both) of these. + +[remainder]: https://exercism.org/docs/programming/operators/remainder +[modulo]: https://en.wikipedia.org/wiki/Modulo_operation +~~~~ + +## How this Exercise is Structured in Python + +This exercise is best solved with Python's `%` ([modulo][modulo]) operator, which returns the remainder of positive integer division. +It has a method equivalent, `operator.mod()` in the [operator module][operator-mod]. + + +Python also offers additional 'remainder' methods in the [math module][math-module]. +[`math.fmod()`][fmod] behaves like `%`, but operates on floats. +[`math.remainder()`][remainder] implements a "step closest to zero" algorithm for the remainder of division. +While we encourage you to get familiar with these methods, neither of these will exactly match the result of `%`, and are not recommended for use with this exercise. + +The built-in function [`divmod()`][divmod] will also give a remainder than matches `%` if used with two positive integers, but returns a `tuple` that needs to be unpacked. + +[divmod]: https://docs.python.org/3/library/functions.html#divmod +[fmod]: https://docs.python.org/3/library/math.html#math.fmod +[math-module]: https://docs.python.org/3/library/math.html +[modulo]: https://www.programiz.com/python-programming/operators#arithmetic +[operator-mod]: https://docs.python.org/3/library/operator.html#operator.mod +[remainder]: https://docs.python.org/3/library/math.html#math.remainder + +## Source + +### Contributed to by + +- @behrtam +- @BethanyG +- @bsoyka +- @cmccandless +- @Dog +- @ikhadykin +- @kytrinyx +- @lowks +- @N-Parsons +- @pheanex +- @sjakobi +- @tqa236 +- @yawpitch + +### Based on + +A variation on FizzBuzz, a famous technical interview question that is intended to weed out potential candidates. That question is itself derived from Fizz Buzz, a popular children's game for teaching division. - https://en.wikipedia.org/wiki/Fizz_buzz \ No newline at end of file diff --git a/python/raindrops/__pycache__/raindrops.cpython-313.pyc b/python/raindrops/__pycache__/raindrops.cpython-313.pyc new file mode 100644 index 0000000..c9c5e55 Binary files /dev/null and b/python/raindrops/__pycache__/raindrops.cpython-313.pyc differ diff --git a/python/raindrops/__pycache__/raindrops.cpython-314.pyc b/python/raindrops/__pycache__/raindrops.cpython-314.pyc new file mode 100644 index 0000000..70a615b Binary files /dev/null and b/python/raindrops/__pycache__/raindrops.cpython-314.pyc differ diff --git a/python/raindrops/__pycache__/raindrops_test.cpython-313-pytest-8.3.4.pyc b/python/raindrops/__pycache__/raindrops_test.cpython-313-pytest-8.3.4.pyc new file mode 100644 index 0000000..ed26fef Binary files /dev/null and b/python/raindrops/__pycache__/raindrops_test.cpython-313-pytest-8.3.4.pyc differ diff --git a/python/raindrops/__pycache__/raindrops_test.cpython-314-pytest-9.1.0.pyc b/python/raindrops/__pycache__/raindrops_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..edbec0e Binary files /dev/null and b/python/raindrops/__pycache__/raindrops_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/raindrops/raindrops.py b/python/raindrops/raindrops.py new file mode 100644 index 0000000..7e0b365 --- /dev/null +++ b/python/raindrops/raindrops.py @@ -0,0 +1,11 @@ +def convert(number): + raindrop_sound: str = "" + if not number % 3: + raindrop_sound += "Pling" + if not number % 5: + raindrop_sound += "Plang" + if not number % 7: + raindrop_sound += "Plong" + if raindrop_sound == "": + raindrop_sound = str(number) + return raindrop_sound diff --git a/python/raindrops/raindrops_test.py b/python/raindrops/raindrops_test.py new file mode 100644 index 0000000..b07e70d --- /dev/null +++ b/python/raindrops/raindrops_test.py @@ -0,0 +1,67 @@ +# These tests are auto-generated with test data from: +# https://github.com/exercism/problem-specifications/tree/main/exercises/raindrops/canonical-data.json +# File last updated on 2023-07-19 + +import unittest + +from raindrops import ( + convert, +) + + +class RaindropsTest(unittest.TestCase): + def test_the_sound_for_1_is_1(self): + self.assertEqual(convert(1), "1") + + def test_the_sound_for_3_is_pling(self): + self.assertEqual(convert(3), "Pling") + + def test_the_sound_for_5_is_plang(self): + self.assertEqual(convert(5), "Plang") + + def test_the_sound_for_7_is_plong(self): + self.assertEqual(convert(7), "Plong") + + def test_the_sound_for_6_is_pling_as_it_has_a_factor_3(self): + self.assertEqual(convert(6), "Pling") + + def test_2_to_the_power_3_does_not_make_a_raindrop_sound_as_3_is_the_exponent_not_the_base( + self, + ): + self.assertEqual(convert(8), "8") + + def test_the_sound_for_9_is_pling_as_it_has_a_factor_3(self): + self.assertEqual(convert(9), "Pling") + + def test_the_sound_for_10_is_plang_as_it_has_a_factor_5(self): + self.assertEqual(convert(10), "Plang") + + def test_the_sound_for_14_is_plong_as_it_has_a_factor_of_7(self): + self.assertEqual(convert(14), "Plong") + + def test_the_sound_for_15_is_pling_plang_as_it_has_factors_3_and_5(self): + self.assertEqual(convert(15), "PlingPlang") + + def test_the_sound_for_21_is_pling_plong_as_it_has_factors_3_and_7(self): + self.assertEqual(convert(21), "PlingPlong") + + def test_the_sound_for_25_is_plang_as_it_has_a_factor_5(self): + self.assertEqual(convert(25), "Plang") + + def test_the_sound_for_27_is_pling_as_it_has_a_factor_3(self): + self.assertEqual(convert(27), "Pling") + + def test_the_sound_for_35_is_plang_plong_as_it_has_factors_5_and_7(self): + self.assertEqual(convert(35), "PlangPlong") + + def test_the_sound_for_49_is_plong_as_it_has_a_factor_7(self): + self.assertEqual(convert(49), "Plong") + + def test_the_sound_for_52_is_52(self): + self.assertEqual(convert(52), "52") + + def test_the_sound_for_105_is_pling_plang_plong_as_it_has_factors_3_5_and_7(self): + self.assertEqual(convert(105), "PlingPlangPlong") + + def test_the_sound_for_3125_is_plang_as_it_has_a_factor_5(self): + self.assertEqual(convert(3125), "Plang") diff --git a/python/resistor-color-duo/.exercism/config.json b/python/resistor-color-duo/.exercism/config.json new file mode 100644 index 0000000..f8177d2 --- /dev/null +++ b/python/resistor-color-duo/.exercism/config.json @@ -0,0 +1,27 @@ +{ + "authors": [ + "ee7" + ], + "contributors": [ + "alirezaghey", + "BethanyG", + "cmccandless", + "Dog", + "xitanggg", + "yawpitch" + ], + "files": { + "solution": [ + "resistor_color_duo.py" + ], + "test": [ + "resistor_color_duo_test.py" + ], + "example": [ + ".meta/example.py" + ] + }, + "blurb": "Convert color codes, as used on resistors, to a numeric value.", + "source": "Maud de Vries, Erik Schierboom", + "source_url": "https://github.com/exercism/problem-specifications/issues/1464" +} diff --git a/python/resistor-color-duo/.exercism/metadata.json b/python/resistor-color-duo/.exercism/metadata.json new file mode 100644 index 0000000..cd58311 --- /dev/null +++ b/python/resistor-color-duo/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"resistor-color-duo","id":"ec4af9062fb3463cab1c7ff884a85bd6","url":"https://exercism.org/tracks/python/exercises/resistor-color-duo","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/resistor-color-duo/HELP.md b/python/resistor-color-duo/HELP.md new file mode 100644 index 0000000..b9f3bb1 --- /dev/null +++ b/python/resistor-color-duo/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +<br> + +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit resistor_color_duo.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/resistor-color-duo/README.md b/python/resistor-color-duo/README.md new file mode 100644 index 0000000..5dac4aa --- /dev/null +++ b/python/resistor-color-duo/README.md @@ -0,0 +1,57 @@ +# Resistor Color Duo + +Welcome to Resistor Color Duo on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Instructions + +If you want to build something using a Raspberry Pi, you'll probably use _resistors_. +For this exercise, you need to know two things about them: + +- Each resistor has a resistance value. +- Resistors are small - so small in fact that if you printed the resistance value on them, it would be hard to read. + +To get around this problem, manufacturers print color-coded bands onto the resistors to denote their resistance values. +Each band has a position and a numeric value. + +The first 2 bands of a resistor have a simple encoding scheme: each color maps to a single number. +For example, if they printed a brown band (value 1) followed by a green band (value 5), it would translate to the number 15. + +In this exercise you are going to create a helpful program so that you don't have to remember the values of the bands. +The program will take color names as input and output a two digit number, even if the input is more than two colors! + +The band colors are encoded as follows: + +- black: 0 +- brown: 1 +- red: 2 +- orange: 3 +- yellow: 4 +- green: 5 +- blue: 6 +- violet: 7 +- grey: 8 +- white: 9 + +From the example above: +brown-green should return 15, and +brown-green-violet should return 15 too, ignoring the third color. + +## Source + +### Created by + +- @ee7 + +### Contributed to by + +- @alirezaghey +- @BethanyG +- @cmccandless +- @Dog +- @xitanggg +- @yawpitch + +### Based on + +Maud de Vries, Erik Schierboom - https://github.com/exercism/problem-specifications/issues/1464 \ No newline at end of file diff --git a/python/resistor-color-duo/__pycache__/resistor_color_duo.cpython-313.pyc b/python/resistor-color-duo/__pycache__/resistor_color_duo.cpython-313.pyc new file mode 100644 index 0000000..e384d4a Binary files /dev/null and b/python/resistor-color-duo/__pycache__/resistor_color_duo.cpython-313.pyc differ diff --git a/python/resistor-color-duo/__pycache__/resistor_color_duo.cpython-314.pyc b/python/resistor-color-duo/__pycache__/resistor_color_duo.cpython-314.pyc new file mode 100644 index 0000000..8a7daab Binary files /dev/null and b/python/resistor-color-duo/__pycache__/resistor_color_duo.cpython-314.pyc differ diff --git a/python/resistor-color-duo/__pycache__/resistor_color_duo_test.cpython-313-pytest-8.3.4.pyc b/python/resistor-color-duo/__pycache__/resistor_color_duo_test.cpython-313-pytest-8.3.4.pyc new file mode 100644 index 0000000..e137c93 Binary files /dev/null and b/python/resistor-color-duo/__pycache__/resistor_color_duo_test.cpython-313-pytest-8.3.4.pyc differ diff --git a/python/resistor-color-duo/__pycache__/resistor_color_duo_test.cpython-314-pytest-9.1.0.pyc b/python/resistor-color-duo/__pycache__/resistor_color_duo_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..6d6c732 Binary files /dev/null and b/python/resistor-color-duo/__pycache__/resistor_color_duo_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/resistor-color-duo/resistor_color_duo.py b/python/resistor-color-duo/resistor_color_duo.py new file mode 100644 index 0000000..be42c68 --- /dev/null +++ b/python/resistor-color-duo/resistor_color_duo.py @@ -0,0 +1,19 @@ +def value(colors): + value: str = "" + color_list: list = [ + "black", + "brown", + "red", + "orange", + "yellow", + "green", + "blue", + "violet", + "grey", + "white", + ] + for band_number, color_band in enumerate(colors): + if band_number > 1: + break + value += str(color_list.index(color_band)) + return int(value) diff --git a/python/resistor-color-duo/resistor_color_duo_test.py b/python/resistor-color-duo/resistor_color_duo_test.py new file mode 100644 index 0000000..5a67016 --- /dev/null +++ b/python/resistor-color-duo/resistor_color_duo_test.py @@ -0,0 +1,32 @@ +# These tests are auto-generated with test data from: +# https://github.com/exercism/problem-specifications/tree/main/exercises/resistor-color-duo/canonical-data.json +# File last updated on 2023-07-19 + +import unittest + +from resistor_color_duo import ( + value, +) + + +class ResistorColorDuoTest(unittest.TestCase): + def test_brown_and_black(self): + self.assertEqual(value(["brown", "black"]), 10) + + def test_blue_and_grey(self): + self.assertEqual(value(["blue", "grey"]), 68) + + def test_yellow_and_violet(self): + self.assertEqual(value(["yellow", "violet"]), 47) + + def test_white_and_red(self): + self.assertEqual(value(["white", "red"]), 92) + + def test_orange_and_orange(self): + self.assertEqual(value(["orange", "orange"]), 33) + + def test_ignore_additional_colors(self): + self.assertEqual(value(["green", "brown", "orange"]), 51) + + def test_black_and_brown_one_digit(self): + self.assertEqual(value(["black", "brown"]), 1) diff --git a/python/resistor-color-expert/.exercism/config.json b/python/resistor-color-expert/.exercism/config.json new file mode 100644 index 0000000..edf50b4 --- /dev/null +++ b/python/resistor-color-expert/.exercism/config.json @@ -0,0 +1,20 @@ +{ + "authors": [ + "meatball133", + "bethanyg" + ], + "files": { + "solution": [ + "resistor_color_expert.py" + ], + "test": [ + "resistor_color_expert_test.py" + ], + "example": [ + ".meta/example.py" + ] + }, + "blurb": "Convert color codes as used on resistors with different bands to a human-readable label.", + "source": "Based on earlier resistor color exercises made by Erik Schierboom and Maud de Vries", + "source_url": "https://github.com/exercism/problem-specifications/issues/1464" +} diff --git a/python/resistor-color-expert/.exercism/metadata.json b/python/resistor-color-expert/.exercism/metadata.json new file mode 100644 index 0000000..8119ec3 --- /dev/null +++ b/python/resistor-color-expert/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"resistor-color-expert","id":"89783c148cda4c0cac551639b1ee1c0b","url":"https://exercism.org/tracks/python/exercises/resistor-color-expert","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/resistor-color-expert/HELP.md b/python/resistor-color-expert/HELP.md new file mode 100644 index 0000000..c2c28ac --- /dev/null +++ b/python/resistor-color-expert/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +<br> + +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit resistor_color_expert.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/resistor-color-expert/README.md b/python/resistor-color-expert/README.md new file mode 100644 index 0000000..ea47196 --- /dev/null +++ b/python/resistor-color-expert/README.md @@ -0,0 +1,113 @@ +# Resistor Color Expert + +Welcome to Resistor Color Expert on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Introduction + +If you want to build something using a Raspberry Pi, you'll probably use _resistors_. +Like the previous [`Resistor Color Duo`][resistor-color-duo-exercise] and [`Resistor Color Trio`][resistor-color-trio-exercise] exercises, you will be translating resistor color bands to human-readable labels. + +- Each resistor has a resistance value. +- Resistors are small - so small in fact that if you printed the resistance value on them, it would be hard to read. + To get around this problem, manufacturers print color-coded bands onto the resistors to denote their resistance values. +- Each band acts as a digit of a number. + For example, if they printed a brown band (value 1) followed by a green band (value 5), it would translate to the number 15. + + +[resistor-color-duo-exercise]: https://exercism.org/tracks/python/exercises/resistor-color-duo +[resistor-color-trio-exercise]: https://exercism.org/tracks/python/exercises/resistor-color-trio + +## Instructions + +In this exercise, you are going to create a helpful program so that you don't have to remember the values of the bands. +The program will take 1, 4, or 5 colors as input and output the correct value in ohms. +The color bands are encoded as follows: + +- black: 0 +- brown: 1 +- red: 2 +- orange: 3 +- yellow: 4 +- green: 5 +- blue: 6 +- violet: 7 +- grey: 8 +- white: 9 + +In [`Resistor Color Trio`][resistor-color-trio-exercise] you decoded the first three color bands. +For instance: orange-orange-brown translated to the main value `330`. +In this exercise you will need to add _tolerance_ to the mix. +Tolerance is the maximum amount that a value can be above or below the main value. +For example, if the last band is green, the maximum tolerance will be `±0.5%`. + +The tolerance band will have one of these values: + +- grey - 0.05% +- violet - 0.1% +- blue - 0.25% +- green - 0.5% +- brown - 1% +- red - 2% +- gold - 5% +- silver - 10% + +The four-band resistor is built up like this: + +| Band_1 | Band_2 | Band_3 | band_4 | +| ------- | ------- | ---------- | --------- | +| Value_1 | Value_2 | Multiplier | Tolerance | + +Examples: + +- orange-orange-brown-green would be `330` ohms with a `±0.5%` tolerance. +- orange-orange-red-grey would be `3300` ohms with `±0.05%` tolerance. + +The difference between a four and five-band resistor is that the five-band resistor has an extra band to indicate a more precise value. + +| Band_1 | Band_2 | Band_3 | Band_4 | band_5 | +| ------- | ------- | ------- | ---------- | --------- | +| Value_1 | Value_2 | Value_3 | Multiplier | Tolerance | + +Examples: + +- orange-orange-orange-black-green would be `333` ohms with a `±0.5%` tolerance. +- orange-red-orange-blue-violet would be `323M` ohms with a `±0.10` tolerance. + +There are also one band resistors. +One band resistors only have the color black with a value of 0. + + +Your program should translate an input `list` of resistor band colors into a label: + +"... ohms ...%" + +So an input `list` of `["orange", "orange", "black", "green"]` should return: + +"33 ohms ±0.5%" + +When there are more than a thousand ohms, we say "kiloohms". + That's similar to saying "kilometer" for 1000 meters, and "kilograms" for 1000 grams. + +So an input `list` of `["orange", "orange", "orange", "grey"]` should return: + +"33 kiloohms ±0.05%" + +When there are more than a million ohms, we say "megaohms". + +So an input `list` of `["orange", "orange", "blue", "red"]` should return: + +"33 megaohms ±2%" + +[resistor-color-trio-exercise]: https://exercism.org/tracks/python/exercises/resistor-color-trio + +## Source + +### Created by + +- @meatball133 +- @bethanyg + +### Based on + +Based on earlier resistor color exercises made by Erik Schierboom and Maud de Vries - https://github.com/exercism/problem-specifications/issues/1464 \ No newline at end of file diff --git a/python/resistor-color-expert/__pycache__/resistor_color_expert.cpython-313.pyc b/python/resistor-color-expert/__pycache__/resistor_color_expert.cpython-313.pyc new file mode 100644 index 0000000..9fdeb65 Binary files /dev/null and b/python/resistor-color-expert/__pycache__/resistor_color_expert.cpython-313.pyc differ diff --git a/python/resistor-color-expert/__pycache__/resistor_color_expert.cpython-314.pyc b/python/resistor-color-expert/__pycache__/resistor_color_expert.cpython-314.pyc new file mode 100644 index 0000000..6ee163e Binary files /dev/null and b/python/resistor-color-expert/__pycache__/resistor_color_expert.cpython-314.pyc differ diff --git a/python/resistor-color-expert/__pycache__/resistor_color_expert_test.cpython-313-pytest-8.3.4.pyc b/python/resistor-color-expert/__pycache__/resistor_color_expert_test.cpython-313-pytest-8.3.4.pyc new file mode 100644 index 0000000..9d7d178 Binary files /dev/null and b/python/resistor-color-expert/__pycache__/resistor_color_expert_test.cpython-313-pytest-8.3.4.pyc differ diff --git a/python/resistor-color-expert/__pycache__/resistor_color_expert_test.cpython-314-pytest-9.1.0.pyc b/python/resistor-color-expert/__pycache__/resistor_color_expert_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..822f7d9 Binary files /dev/null and b/python/resistor-color-expert/__pycache__/resistor_color_expert_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/resistor-color-expert/resistor_color_expert.py b/python/resistor-color-expert/resistor_color_expert.py new file mode 100644 index 0000000..ad2e964 --- /dev/null +++ b/python/resistor-color-expert/resistor_color_expert.py @@ -0,0 +1,55 @@ +def resistor_label(colors): + band_colors: list = [ + "black", + "brown", + "red", + "orange", + "yellow", + "green", + "blue", + "violet", + "grey", + "white", + ] + tolerances: dict = { + "grey": " ±0.05%", + "violet": " ±0.1%", + "blue": " ±0.25%", + "green": " ±0.5%", + "brown": " ±1%", + "red": " ±2%", + "gold": " ±5%", + "silver": " ±10%", + } + band_size: int = len(colors) + # if band_size > 4 or band_size < 2: + # print("total number of bands must be between 4 or 5") + valor_bandas: list[str] = [] + valor_total: float = 0.00 + multiplier: int = 0 + tolerance: str = "" + metrix_prefix: str + for band_number, color in enumerate(colors): + if band_size > 2: + if band_number == band_size - 2: + multiplier = band_colors.index(color) + elif band_number == band_size - 1: + tolerance = tolerances[color] + else: + valor_bandas.append(str(band_colors.index(color))) + else: + valor_bandas.append(str(band_colors.index(color))) + valor_total = int("".join(valor_bandas)) * (10**multiplier) + # apply sieve to determine metrix prefix + if valor_total >= 10**9: + metrix_prefix = "giga" + valor_total /= 10**9 + elif valor_total >= 10**6: + metrix_prefix = "mega" + valor_total /= 10**6 + elif valor_total >= 10**3: + metrix_prefix = "kilo" + valor_total /= 10**3 + else: + metrix_prefix = "" + return f"{valor_total if valor_total != int(valor_total) else int(valor_total)} {metrix_prefix}ohms{tolerance}" diff --git a/python/resistor-color-expert/resistor_color_expert_test.py b/python/resistor-color-expert/resistor_color_expert_test.py new file mode 100644 index 0000000..47e7fc6 --- /dev/null +++ b/python/resistor-color-expert/resistor_color_expert_test.py @@ -0,0 +1,61 @@ +import unittest + +from resistor_color_expert import ( + resistor_label, +) + +# Tests adapted from `problem-specifications//canonical-data.json` + + +class ResistorColorExpertTest(unittest.TestCase): + def test_orange_orange_black_and_red(self): + self.assertEqual(resistor_label(["orange", "orange", "black", "red"]), "33 ohms ±2%") + + def test_blue_grey_brown_and_violet(self): + self.assertEqual(resistor_label(["blue", "grey", "brown", "violet"]), "680 ohms ±0.1%") + + def test_red_black_red_and_green(self): + self.assertEqual(resistor_label(["red", "black", "red", "green"]), "2 kiloohms ±0.5%") + + def test_green_brown_orange_and_grey(self): + self.assertEqual( + resistor_label(["green", "brown", "orange", "grey"]), "51 kiloohms ±0.05%" + ) + + def test_one_black_band(self): + self.assertEqual(resistor_label(["black"]), "0 ohms") + + def test_orange_orange_yellow_black_and_brown(self): + self.assertEqual( + resistor_label(["orange", "orange", "yellow", "black", "brown"]), "334 ohms ±1%" + ) + + def test_red_green_yellow_yellow_and_brown(self): + self.assertEqual( + resistor_label(["red", "green", "yellow", "yellow", "brown"]), "2.54 megaohms ±1%" + ) + + def test_blue_grey_white_brown_and_brown(self): + self.assertEqual( + resistor_label(["blue", "grey", "white", "brown", "brown"]), "6.89 kiloohms ±1%" + ) + + def test_violet_orange_red_and_grey(self): + self.assertEqual( + resistor_label(["violet", "orange", "red", "grey"]), "7.3 kiloohms ±0.05%" + ) + + def test_brown_red_orange_green_and_blue(self): + self.assertEqual( + resistor_label(["brown", "red", "orange", "green", "blue"]), "12.3 megaohms ±0.25%" + ) + + def test_brown_black_brown_yellow_and_violet(self): + self.assertEqual( + resistor_label(["brown", "black", "brown", "yellow", "violet"]), "1.01 megaohms ±0.1%" + ) + + def test_brown_black_red_and_red(self): + self.assertEqual( + resistor_label(["brown", "black", "red", "red"]), "1 kiloohms ±2%" + ) diff --git a/python/resistor-color-trio/.exercism/config.json b/python/resistor-color-trio/.exercism/config.json new file mode 100644 index 0000000..68dad4c --- /dev/null +++ b/python/resistor-color-trio/.exercism/config.json @@ -0,0 +1,20 @@ +{ + "authors": [ + "meatball133", + "bethanyg" + ], + "files": { + "solution": [ + "resistor_color_trio.py" + ], + "test": [ + "resistor_color_trio_test.py" + ], + "example": [ + ".meta/example.py" + ] + }, + "blurb": "Convert color codes, as used on resistors, to a human-readable label.", + "source": "Maud de Vries, Erik Schierboom", + "source_url": "https://github.com/exercism/problem-specifications/issues/1549" +} diff --git a/python/resistor-color-trio/.exercism/metadata.json b/python/resistor-color-trio/.exercism/metadata.json new file mode 100644 index 0000000..29da236 --- /dev/null +++ b/python/resistor-color-trio/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"resistor-color-trio","id":"b0bb28b9dda84bff94ed34d74469c591","url":"https://exercism.org/tracks/python/exercises/resistor-color-trio","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/resistor-color-trio/HELP.md b/python/resistor-color-trio/HELP.md new file mode 100644 index 0000000..f902ec5 --- /dev/null +++ b/python/resistor-color-trio/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +<br> + +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit resistor_color_trio.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/resistor-color-trio/README.md b/python/resistor-color-trio/README.md new file mode 100644 index 0000000..91ea6c0 --- /dev/null +++ b/python/resistor-color-trio/README.md @@ -0,0 +1,72 @@ +# Resistor Color Trio + +Welcome to Resistor Color Trio on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Instructions + +If you want to build something using a Raspberry Pi, you'll probably use _resistors_. +For this exercise, you need to know only three things about them: + +- Each resistor has a resistance value. +- Resistors are small - so small in fact that if you printed the resistance value on them, it would be hard to read. + To get around this problem, manufacturers print color-coded bands onto the resistors to denote their resistance values. +- Each band acts as a digit of a number. + For example, if they printed a brown band (value 1) followed by a green band (value 5), it would translate to the number 15. + In this exercise, you are going to create a helpful program so that you don't have to remember the values of the bands. + The program will take 3 colors as input, and outputs the correct value, in ohms. + The color bands are encoded as follows: + +- black: 0 +- brown: 1 +- red: 2 +- orange: 3 +- yellow: 4 +- green: 5 +- blue: 6 +- violet: 7 +- grey: 8 +- white: 9 + +In Resistor Color Duo you decoded the first two colors. +For instance: orange-orange got the main value `33`. +The third color stands for how many zeros need to be added to the main value. +The main value plus the zeros gives us a value in ohms. +For the exercise it doesn't matter what ohms really are. +For example: + +- orange-orange-black would be 33 and no zeros, which becomes 33 ohms. +- orange-orange-red would be 33 and 2 zeros, which becomes 3300 ohms. +- orange-orange-orange would be 33 and 3 zeros, which becomes 33000 ohms. + +(If Math is your thing, you may want to think of the zeros as exponents of 10. +If Math is not your thing, go with the zeros. +It really is the same thing, just in plain English instead of Math lingo.) + +This exercise is about translating the colors into a label: + +> "... ohms" + +So an input of `"orange", "orange", "black"` should return: + +> "33 ohms" + +When we get to larger resistors, a [metric prefix][metric-prefix] is used to indicate a larger magnitude of ohms, such as "kiloohms". +That is similar to saying "2 kilometers" instead of "2000 meters", or "2 kilograms" for "2000 grams". + +For example, an input of `"orange", "orange", "orange"` should return: + +> "33 kiloohms" + +[metric-prefix]: https://en.wikipedia.org/wiki/Metric_prefix + +## Source + +### Created by + +- @meatball133 +- @bethanyg + +### Based on + +Maud de Vries, Erik Schierboom - https://github.com/exercism/problem-specifications/issues/1549 \ No newline at end of file diff --git a/python/resistor-color-trio/__pycache__/resistor_color_trio.cpython-313.pyc b/python/resistor-color-trio/__pycache__/resistor_color_trio.cpython-313.pyc new file mode 100644 index 0000000..ae35d22 Binary files /dev/null and b/python/resistor-color-trio/__pycache__/resistor_color_trio.cpython-313.pyc differ diff --git a/python/resistor-color-trio/__pycache__/resistor_color_trio.cpython-314.pyc b/python/resistor-color-trio/__pycache__/resistor_color_trio.cpython-314.pyc new file mode 100644 index 0000000..449c099 Binary files /dev/null and b/python/resistor-color-trio/__pycache__/resistor_color_trio.cpython-314.pyc differ diff --git a/python/resistor-color-trio/__pycache__/resistor_color_trio_test.cpython-313-pytest-8.3.4.pyc b/python/resistor-color-trio/__pycache__/resistor_color_trio_test.cpython-313-pytest-8.3.4.pyc new file mode 100644 index 0000000..c0c8732 Binary files /dev/null and b/python/resistor-color-trio/__pycache__/resistor_color_trio_test.cpython-313-pytest-8.3.4.pyc differ diff --git a/python/resistor-color-trio/__pycache__/resistor_color_trio_test.cpython-314-pytest-9.1.0.pyc b/python/resistor-color-trio/__pycache__/resistor_color_trio_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..5a9995a Binary files /dev/null and b/python/resistor-color-trio/__pycache__/resistor_color_trio_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/resistor-color-trio/resistor_color_trio.py b/python/resistor-color-trio/resistor_color_trio.py new file mode 100644 index 0000000..34e5efc --- /dev/null +++ b/python/resistor-color-trio/resistor_color_trio.py @@ -0,0 +1,38 @@ +def label(colors): + color_list: list = [ + "black", + "brown", + "red", + "orange", + "yellow", + "green", + "blue", + "violet", + "grey", + "white", + ] + value: int = 0 + multiplier: int = 0 + metric_prefix: str = "" + for number, band in enumerate(colors): + if number > 2: + break + elif number > 1: + multiplier = color_list.index(band) + else: + value += color_list.index(band) * (10 ** (1 - number)) + # multiply value by 10 to the power of multiplier + value = value * (10**multiplier) + # run value through a sieve and apply the correct metric_prefix + if value >= 10**9: + value = int(value / (10**9)) + metric_prefix = "giga" + elif value >= 10**6: + value = int(value / (10**6)) + metric_prefix = "mega" + elif value >= 10**3: + value = int(value / (10**3)) + metric_prefix = "kilo" + else: + value = value + return f"{int(value)} {metric_prefix}ohms" diff --git a/python/resistor-color-trio/resistor_color_trio_test.py b/python/resistor-color-trio/resistor_color_trio_test.py new file mode 100644 index 0000000..05f7942 --- /dev/null +++ b/python/resistor-color-trio/resistor_color_trio_test.py @@ -0,0 +1,41 @@ +# These tests are auto-generated with test data from: +# https://github.com/exercism/problem-specifications/tree/main/exercises/resistor-color-trio/canonical-data.json +# File last updated on 2023-07-19 + +import unittest + +from resistor_color_trio import ( + label, +) + + +class ResistorColorTrioTest(unittest.TestCase): + def test_orange_and_orange_and_black(self): + self.assertEqual(label(["orange", "orange", "black"]), "33 ohms") + + def test_blue_and_grey_and_brown(self): + self.assertEqual(label(["blue", "grey", "brown"]), "680 ohms") + + def test_red_and_black_and_red(self): + self.assertEqual(label(["red", "black", "red"]), "2 kiloohms") + + def test_green_and_brown_and_orange(self): + self.assertEqual(label(["green", "brown", "orange"]), "51 kiloohms") + + def test_yellow_and_violet_and_yellow(self): + self.assertEqual(label(["yellow", "violet", "yellow"]), "470 kiloohms") + + def test_blue_and_violet_and_blue(self): + self.assertEqual(label(["blue", "violet", "blue"]), "67 megaohms") + + def test_minimum_possible_value(self): + self.assertEqual(label(["black", "black", "black"]), "0 ohms") + + def test_maximum_possible_value(self): + self.assertEqual(label(["white", "white", "white"]), "99 gigaohms") + + def test_first_two_colors_make_an_invalid_octal_number(self): + self.assertEqual(label(["black", "grey", "black"]), "8 ohms") + + def test_ignore_extra_colors(self): + self.assertEqual(label(["blue", "green", "yellow", "orange"]), "650 kiloohms") diff --git a/python/resistor-color/.exercism/config.json b/python/resistor-color/.exercism/config.json new file mode 100644 index 0000000..08c69e1 --- /dev/null +++ b/python/resistor-color/.exercism/config.json @@ -0,0 +1,25 @@ +{ + "authors": [ + "gabriel376" + ], + "contributors": [ + "cmccandless", + "Dog", + "tqa236", + "yawpitch" + ], + "files": { + "solution": [ + "resistor_color.py" + ], + "test": [ + "resistor_color_test.py" + ], + "example": [ + ".meta/example.py" + ] + }, + "blurb": "Convert a resistor band's color to its numeric representation.", + "source": "Maud de Vries, Erik Schierboom", + "source_url": "https://github.com/exercism/problem-specifications/issues/1458" +} diff --git a/python/resistor-color/.exercism/metadata.json b/python/resistor-color/.exercism/metadata.json new file mode 100644 index 0000000..bf8cf9e --- /dev/null +++ b/python/resistor-color/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"resistor-color","id":"787fa1327e5f42e5a84b22c294559356","url":"https://exercism.org/tracks/python/exercises/resistor-color","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/resistor-color/HELP.md b/python/resistor-color/HELP.md new file mode 100644 index 0000000..a7c881d --- /dev/null +++ b/python/resistor-color/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +<br> + +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit resistor_color.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/resistor-color/README.md b/python/resistor-color/README.md new file mode 100644 index 0000000..fcb3af1 --- /dev/null +++ b/python/resistor-color/README.md @@ -0,0 +1,61 @@ +# Resistor Color + +Welcome to Resistor Color on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Instructions + +If you want to build something using a Raspberry Pi, you'll probably use _resistors_. +For this exercise, you need to know two things about them: + +- Each resistor has a resistance value. +- Resistors are small - so small in fact that if you printed the resistance value on them, it would be hard to read. + +To get around this problem, manufacturers print color-coded bands onto the resistors to denote their resistance values. +Each band has a position and a numeric value. + +The first 2 bands of a resistor have a simple encoding scheme: each color maps to a single number. + +In this exercise you are going to create a helpful program so that you don't have to remember the values of the bands. + +These colors are encoded as follows: + +- black: 0 +- brown: 1 +- red: 2 +- orange: 3 +- yellow: 4 +- green: 5 +- blue: 6 +- violet: 7 +- grey: 8 +- white: 9 + +The goal of this exercise is to create a way: + +- to look up the numerical value associated with a particular color band +- to list the different band colors + +Mnemonics map the colors to the numbers, that, when stored as an array, happen to map to their index in the array: +Better Be Right Or Your Great Big Values Go Wrong. + +More information on the color encoding of resistors can be found in the [Electronic color code Wikipedia article][e-color-code]. + +[e-color-code]: https://en.wikipedia.org/wiki/Electronic_color_code + +## Source + +### Created by + +- @gabriel376 + +### Contributed to by + +- @cmccandless +- @Dog +- @tqa236 +- @yawpitch + +### Based on + +Maud de Vries, Erik Schierboom - https://github.com/exercism/problem-specifications/issues/1458 \ No newline at end of file diff --git a/python/resistor-color/__pycache__/resistor_color.cpython-313.pyc b/python/resistor-color/__pycache__/resistor_color.cpython-313.pyc new file mode 100644 index 0000000..9b0632e Binary files /dev/null and b/python/resistor-color/__pycache__/resistor_color.cpython-313.pyc differ diff --git a/python/resistor-color/__pycache__/resistor_color.cpython-314.pyc b/python/resistor-color/__pycache__/resistor_color.cpython-314.pyc new file mode 100644 index 0000000..df66dcd Binary files /dev/null and b/python/resistor-color/__pycache__/resistor_color.cpython-314.pyc differ diff --git a/python/resistor-color/__pycache__/resistor_color_test.cpython-313-pytest-8.3.4.pyc b/python/resistor-color/__pycache__/resistor_color_test.cpython-313-pytest-8.3.4.pyc new file mode 100644 index 0000000..92f02ef Binary files /dev/null and b/python/resistor-color/__pycache__/resistor_color_test.cpython-313-pytest-8.3.4.pyc differ diff --git a/python/resistor-color/__pycache__/resistor_color_test.cpython-314-pytest-9.1.0.pyc b/python/resistor-color/__pycache__/resistor_color_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..132dd6e Binary files /dev/null and b/python/resistor-color/__pycache__/resistor_color_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/resistor-color/resistor_color.py b/python/resistor-color/resistor_color.py new file mode 100644 index 0000000..2fa7155 --- /dev/null +++ b/python/resistor-color/resistor_color.py @@ -0,0 +1,17 @@ +def color_code(color): + return colors().index(color) + + +def colors(): + return [ + "black", + "brown", + "red", + "orange", + "yellow", + "green", + "blue", + "violet", + "grey", + "white", + ] diff --git a/python/resistor-color/resistor_color_test.py b/python/resistor-color/resistor_color_test.py new file mode 100644 index 0000000..d86d755 --- /dev/null +++ b/python/resistor-color/resistor_color_test.py @@ -0,0 +1,36 @@ +# These tests are auto-generated with test data from: +# https://github.com/exercism/problem-specifications/tree/main/exercises/resistor-color/canonical-data.json +# File last updated on 2023-07-19 + +import unittest + +from resistor_color import ( + color_code, + colors, +) + + +class ResistorColorTest(unittest.TestCase): + def test_black(self): + self.assertEqual(color_code("black"), 0) + + def test_white(self): + self.assertEqual(color_code("white"), 9) + + def test_orange(self): + self.assertEqual(color_code("orange"), 3) + + def test_colors(self): + expected = [ + "black", + "brown", + "red", + "orange", + "yellow", + "green", + "blue", + "violet", + "grey", + "white", + ] + self.assertEqual(colors(), expected) diff --git a/python/reverse-string/.exercism/config.json b/python/reverse-string/.exercism/config.json new file mode 100644 index 0000000..bbc16e8 --- /dev/null +++ b/python/reverse-string/.exercism/config.json @@ -0,0 +1,28 @@ +{ + "authors": [ + "sjwarner-bp" + ], + "contributors": [ + "cmccandless", + "dmerejkowsky", + "Dog", + "flores-jacob", + "frerich", + "Grociu", + "tqa236" + ], + "files": { + "solution": [ + "reverse_string.py" + ], + "test": [ + "reverse_string_test.py" + ], + "example": [ + ".meta/example.py" + ] + }, + "blurb": "Reverse a given string.", + "source": "Introductory challenge to reverse an input string", + "source_url": "https://medium.freecodecamp.org/how-to-reverse-a-string-in-javascript-in-3-different-ways-75e4763c68cb" +} diff --git a/python/reverse-string/.exercism/metadata.json b/python/reverse-string/.exercism/metadata.json new file mode 100644 index 0000000..37976e7 --- /dev/null +++ b/python/reverse-string/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"reverse-string","id":"4e196cfe5ddf44c08e0750883774d7df","url":"https://exercism.org/tracks/python/exercises/reverse-string","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/reverse-string/HELP.md b/python/reverse-string/HELP.md new file mode 100644 index 0000000..9cf1656 --- /dev/null +++ b/python/reverse-string/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +<br> + +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit reverse_string.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/reverse-string/README.md b/python/reverse-string/README.md new file mode 100644 index 0000000..fa680db --- /dev/null +++ b/python/reverse-string/README.md @@ -0,0 +1,40 @@ +# Reverse String + +Welcome to Reverse String on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Introduction + +Reversing strings (reading them from right to left, rather than from left to right) is a surprisingly common task in programming. + +For example, in bioinformatics, reversing the sequence of DNA or RNA strings is often important for various analyses, such as finding complementary strands or identifying palindromic sequences that have biological significance. + +## Instructions + +Your task is to reverse a given string. + +Some examples: + +- Turn `"stressed"` into `"desserts"`. +- Turn `"strops"` into `"sports"`. +- Turn `"racecar"` into `"racecar"`. + +## Source + +### Created by + +- @sjwarner-bp + +### Contributed to by + +- @cmccandless +- @dmerejkowsky +- @Dog +- @flores-jacob +- @frerich +- @Grociu +- @tqa236 + +### Based on + +Introductory challenge to reverse an input string - https://medium.freecodecamp.org/how-to-reverse-a-string-in-javascript-in-3-different-ways-75e4763c68cb \ No newline at end of file diff --git a/python/reverse-string/__pycache__/reverse_string.cpython-313.pyc b/python/reverse-string/__pycache__/reverse_string.cpython-313.pyc new file mode 100644 index 0000000..8e57100 Binary files /dev/null and b/python/reverse-string/__pycache__/reverse_string.cpython-313.pyc differ diff --git a/python/reverse-string/__pycache__/reverse_string.cpython-314.pyc b/python/reverse-string/__pycache__/reverse_string.cpython-314.pyc new file mode 100644 index 0000000..0b03e35 Binary files /dev/null and b/python/reverse-string/__pycache__/reverse_string.cpython-314.pyc differ diff --git a/python/reverse-string/__pycache__/reverse_string_test.cpython-313-pytest-8.3.4.pyc b/python/reverse-string/__pycache__/reverse_string_test.cpython-313-pytest-8.3.4.pyc new file mode 100644 index 0000000..7af170b Binary files /dev/null and b/python/reverse-string/__pycache__/reverse_string_test.cpython-313-pytest-8.3.4.pyc differ diff --git a/python/reverse-string/__pycache__/reverse_string_test.cpython-314-pytest-9.1.0.pyc b/python/reverse-string/__pycache__/reverse_string_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..33d51ad Binary files /dev/null and b/python/reverse-string/__pycache__/reverse_string_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/reverse-string/reverse_string.py b/python/reverse-string/reverse_string.py new file mode 100644 index 0000000..574ba55 --- /dev/null +++ b/python/reverse-string/reverse_string.py @@ -0,0 +1,9 @@ +def reverse(text): + # simple method in python + # return text[::-1] + + # other way, create a new string and add from last letter to first letter + reversed_string: str = "" + for index in range(len(text) - 1, -1, -1): + reversed_string += text[index] + return reversed_string diff --git a/python/reverse-string/reverse_string_test.py b/python/reverse-string/reverse_string_test.py new file mode 100644 index 0000000..8316841 --- /dev/null +++ b/python/reverse-string/reverse_string_test.py @@ -0,0 +1,32 @@ +# These tests are auto-generated with test data from: +# https://github.com/exercism/problem-specifications/tree/main/exercises/reverse-string/canonical-data.json +# File last updated on 2024-02-28 + +import unittest + +from reverse_string import ( + reverse, +) + + +class ReverseStringTest(unittest.TestCase): + def test_an_empty_string(self): + self.assertEqual(reverse(""), "") + + def test_a_word(self): + self.assertEqual(reverse("robot"), "tobor") + + def test_a_capitalized_word(self): + self.assertEqual(reverse("Ramen"), "nemaR") + + def test_a_sentence_with_punctuation(self): + self.assertEqual(reverse("I'm hungry!"), "!yrgnuh m'I") + + def test_a_palindrome(self): + self.assertEqual(reverse("racecar"), "racecar") + + def test_an_even_sized_word(self): + self.assertEqual(reverse("drawer"), "reward") + + def test_wide_characters(self): + self.assertEqual(reverse("子猫"), "猫子") diff --git a/python/rna-transcription/.exercism/config.json b/python/rna-transcription/.exercism/config.json new file mode 100644 index 0000000..636aa7e --- /dev/null +++ b/python/rna-transcription/.exercism/config.json @@ -0,0 +1,38 @@ +{ + "authors": [ + "BrianHicks" + ], + "contributors": [ + "behrtam", + "cmccandless", + "davepeake", + "Dog", + "dvermd", + "hariesramdhani", + "ikhadykin", + "jamesmcm", + "kytrinyx", + "lowks", + "magnus-hogberg", + "N-Parsons", + "pheanex", + "sjakobi", + "thomasjpfan", + "tqa236", + "yawpitch" + ], + "files": { + "solution": [ + "rna_transcription.py" + ], + "test": [ + "rna_transcription_test.py" + ], + "example": [ + ".meta/example.py" + ] + }, + "blurb": "Given a DNA strand, return its RNA Complement Transcription.", + "source": "Hyperphysics", + "source_url": "https://web.archive.org/web/20220408112140/http://hyperphysics.phy-astr.gsu.edu/hbase/Organic/transcription.html" +} diff --git a/python/rna-transcription/.exercism/metadata.json b/python/rna-transcription/.exercism/metadata.json new file mode 100644 index 0000000..9b35554 --- /dev/null +++ b/python/rna-transcription/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"rna-transcription","id":"8eda9b26743f42e99db563cceb0fb477","url":"https://exercism.org/tracks/python/exercises/rna-transcription","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/rna-transcription/HELP.md b/python/rna-transcription/HELP.md new file mode 100644 index 0000000..bc61ffc --- /dev/null +++ b/python/rna-transcription/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +<br> + +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit rna_transcription.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/rna-transcription/README.md b/python/rna-transcription/README.md new file mode 100644 index 0000000..b50f805 --- /dev/null +++ b/python/rna-transcription/README.md @@ -0,0 +1,72 @@ +# RNA Transcription + +Welcome to RNA Transcription on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Introduction + +You work for a bioengineering company that specializes in developing therapeutic solutions. + +Your team has just been given a new project to develop a targeted therapy for a rare type of cancer. + +~~~~exercism/note +It's all very complicated, but the basic idea is that sometimes people's bodies produce too much of a given protein. +That can cause all sorts of havoc. + +But if you can create a very specific molecule (called a micro-RNA), it can prevent the protein from being produced. + +This technique is called [RNA Interference][rnai]. + +[rnai]: https://admin.acceleratingscience.com/ask-a-scientist/what-is-rnai/ +~~~~ + +## Instructions + +Your task is to determine the RNA complement of a given DNA sequence. + +Both DNA and RNA strands are a sequence of nucleotides. + +The four nucleotides found in DNA are adenine (**A**), cytosine (**C**), guanine (**G**), and thymine (**T**). + +The four nucleotides found in RNA are adenine (**A**), cytosine (**C**), guanine (**G**), and uracil (**U**). + +Given a DNA strand, its transcribed RNA strand is formed by replacing each nucleotide with its complement: + +- `G` -> `C` +- `C` -> `G` +- `T` -> `A` +- `A` -> `U` + +~~~~exercism/note +If you want to look at how the inputs and outputs are structured, take a look at the examples in the test suite. +~~~~ + +## Source + +### Created by + +- @BrianHicks + +### Contributed to by + +- @behrtam +- @cmccandless +- @davepeake +- @Dog +- @dvermd +- @hariesramdhani +- @ikhadykin +- @jamesmcm +- @kytrinyx +- @lowks +- @magnus-hogberg +- @N-Parsons +- @pheanex +- @sjakobi +- @thomasjpfan +- @tqa236 +- @yawpitch + +### Based on + +Hyperphysics - https://web.archive.org/web/20220408112140/http://hyperphysics.phy-astr.gsu.edu/hbase/Organic/transcription.html \ No newline at end of file diff --git a/python/rna-transcription/__pycache__/rna_transcription.cpython-313.pyc b/python/rna-transcription/__pycache__/rna_transcription.cpython-313.pyc new file mode 100644 index 0000000..7adf70c Binary files /dev/null and b/python/rna-transcription/__pycache__/rna_transcription.cpython-313.pyc differ diff --git a/python/rna-transcription/__pycache__/rna_transcription.cpython-314.pyc b/python/rna-transcription/__pycache__/rna_transcription.cpython-314.pyc new file mode 100644 index 0000000..04af3fa Binary files /dev/null and b/python/rna-transcription/__pycache__/rna_transcription.cpython-314.pyc differ diff --git a/python/rna-transcription/__pycache__/rna_transcription_test.cpython-313-pytest-8.3.4.pyc b/python/rna-transcription/__pycache__/rna_transcription_test.cpython-313-pytest-8.3.4.pyc new file mode 100644 index 0000000..ceef8eb Binary files /dev/null and b/python/rna-transcription/__pycache__/rna_transcription_test.cpython-313-pytest-8.3.4.pyc differ diff --git a/python/rna-transcription/__pycache__/rna_transcription_test.cpython-314-pytest-9.1.0.pyc b/python/rna-transcription/__pycache__/rna_transcription_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..5cf7ce8 Binary files /dev/null and b/python/rna-transcription/__pycache__/rna_transcription_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/rna-transcription/rna_transcription.py b/python/rna-transcription/rna_transcription.py new file mode 100644 index 0000000..f374e13 --- /dev/null +++ b/python/rna-transcription/rna_transcription.py @@ -0,0 +1,18 @@ +from unittest import defaultTestLoader + + +def to_rna(dna_strand): + transcribed_rna_strand: str = "" + for nucleotide in dna_strand: + match nucleotide: + case "G": + transcribed_rna_strand += "C" + case "C": + transcribed_rna_strand += "G" + case "T": + transcribed_rna_strand += "A" + case "A": + transcribed_rna_strand += "U" + case _: + transcribed_rna_strand += nucleotide + return transcribed_rna_strand diff --git a/python/rna-transcription/rna_transcription_test.py b/python/rna-transcription/rna_transcription_test.py new file mode 100644 index 0000000..766f202 --- /dev/null +++ b/python/rna-transcription/rna_transcription_test.py @@ -0,0 +1,29 @@ +# These tests are auto-generated with test data from: +# https://github.com/exercism/problem-specifications/tree/main/exercises/rna-transcription/canonical-data.json +# File last updated on 2023-07-19 + +import unittest + +from rna_transcription import ( + to_rna, +) + + +class RnaTranscriptionTest(unittest.TestCase): + def test_empty_rna_sequence(self): + self.assertEqual(to_rna(""), "") + + def test_rna_complement_of_cytosine_is_guanine(self): + self.assertEqual(to_rna("C"), "G") + + def test_rna_complement_of_guanine_is_cytosine(self): + self.assertEqual(to_rna("G"), "C") + + def test_rna_complement_of_thymine_is_adenine(self): + self.assertEqual(to_rna("T"), "A") + + def test_rna_complement_of_adenine_is_uracil(self): + self.assertEqual(to_rna("A"), "U") + + def test_rna_complement(self): + self.assertEqual(to_rna("ACGTGGTCTTAA"), "UGCACCAGAAUU") diff --git a/python/rotational-cipher/.exercism/config.json b/python/rotational-cipher/.exercism/config.json new file mode 100644 index 0000000..d21c3ca --- /dev/null +++ b/python/rotational-cipher/.exercism/config.json @@ -0,0 +1,30 @@ +{ + "authors": [ + "krapes" + ], + "contributors": [ + "akashsara", + "behrtam", + "cmccandless", + "Dog", + "dotrungkien", + "ikhadykin", + "lekum", + "N-Parsons", + "tqa236" + ], + "files": { + "solution": [ + "rotational_cipher.py" + ], + "test": [ + "rotational_cipher_test.py" + ], + "example": [ + ".meta/example.py" + ] + }, + "blurb": "Create an implementation of the rotational cipher, also sometimes called the Caesar cipher.", + "source": "Wikipedia", + "source_url": "https://en.wikipedia.org/wiki/Caesar_cipher" +} diff --git a/python/rotational-cipher/.exercism/metadata.json b/python/rotational-cipher/.exercism/metadata.json new file mode 100644 index 0000000..4e45cb8 --- /dev/null +++ b/python/rotational-cipher/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"rotational-cipher","id":"ade3f790ca03464c88e8bbf0174e1cc9","url":"https://exercism.org/tracks/python/exercises/rotational-cipher","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/rotational-cipher/HELP.md b/python/rotational-cipher/HELP.md new file mode 100644 index 0000000..d45cf55 --- /dev/null +++ b/python/rotational-cipher/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +<br> + +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit rotational_cipher.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/rotational-cipher/README.md b/python/rotational-cipher/README.md new file mode 100644 index 0000000..e86902c --- /dev/null +++ b/python/rotational-cipher/README.md @@ -0,0 +1,56 @@ +# Rotational Cipher + +Welcome to Rotational Cipher on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Instructions + +Create an implementation of the rotational cipher, also sometimes called the Caesar cipher. + +The Caesar cipher is a simple shift cipher that relies on transposing all the letters in the alphabet using an integer key between `0` and `26`. +Using a key of `0` or `26` will always yield the same output due to modular arithmetic. +The letter is shifted for as many values as the value of the key. + +The general notation for rotational ciphers is `ROT + <key>`. +The most commonly used rotational cipher is `ROT13`. + +A `ROT13` on the Latin alphabet would be as follows: + +```text +Plain: abcdefghijklmnopqrstuvwxyz +Cipher: nopqrstuvwxyzabcdefghijklm +``` + +It is stronger than the Atbash cipher because it has 27 possible keys, and 25 usable keys. + +Ciphertext is written out in the same formatting as the input including spaces and punctuation. + +## Examples + +- ROT5 `omg` gives `trl` +- ROT0 `c` gives `c` +- ROT26 `Cool` gives `Cool` +- ROT13 `The quick brown fox jumps over the lazy dog.` gives `Gur dhvpx oebja sbk whzcf bire gur ynml qbt.` +- ROT13 `Gur dhvpx oebja sbk whzcf bire gur ynml qbt.` gives `The quick brown fox jumps over the lazy dog.` + +## Source + +### Created by + +- @krapes + +### Contributed to by + +- @akashsara +- @behrtam +- @cmccandless +- @Dog +- @dotrungkien +- @ikhadykin +- @lekum +- @N-Parsons +- @tqa236 + +### Based on + +Wikipedia - https://en.wikipedia.org/wiki/Caesar_cipher \ No newline at end of file diff --git a/python/rotational-cipher/__pycache__/rotational_cipher.cpython-313.pyc b/python/rotational-cipher/__pycache__/rotational_cipher.cpython-313.pyc new file mode 100644 index 0000000..ef37fd5 Binary files /dev/null and b/python/rotational-cipher/__pycache__/rotational_cipher.cpython-313.pyc differ diff --git a/python/rotational-cipher/__pycache__/rotational_cipher.cpython-314.pyc b/python/rotational-cipher/__pycache__/rotational_cipher.cpython-314.pyc new file mode 100644 index 0000000..ae2dec5 Binary files /dev/null and b/python/rotational-cipher/__pycache__/rotational_cipher.cpython-314.pyc differ diff --git a/python/rotational-cipher/__pycache__/rotational_cipher_test.cpython-313-pytest-8.3.4.pyc b/python/rotational-cipher/__pycache__/rotational_cipher_test.cpython-313-pytest-8.3.4.pyc new file mode 100644 index 0000000..661cdb7 Binary files /dev/null and b/python/rotational-cipher/__pycache__/rotational_cipher_test.cpython-313-pytest-8.3.4.pyc differ diff --git a/python/rotational-cipher/__pycache__/rotational_cipher_test.cpython-314-pytest-9.1.0.pyc b/python/rotational-cipher/__pycache__/rotational_cipher_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..5283e91 Binary files /dev/null and b/python/rotational-cipher/__pycache__/rotational_cipher_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/rotational-cipher/rotational_cipher.py b/python/rotational-cipher/rotational_cipher.py new file mode 100644 index 0000000..7d2dbbe --- /dev/null +++ b/python/rotational-cipher/rotational_cipher.py @@ -0,0 +1,19 @@ +def rotate(text, key): + cyphertext: str = "" + for letter in text: + if letter.isalpha(): + # check if letter is uppercase or lower case, + # and set add_value accordingly + if ord(letter) >= ord("A") and ord(letter) <= ord("Z"): + add_value = ord("A") + else: + add_value = ord("a") + # mod_value + mod_value = add_value + 26 + cyphertext += chr( + ((ord(letter) + key) % mod_value) + + (((ord(letter) + key) // mod_value) * add_value) + ) + else: + cyphertext += letter + return cyphertext diff --git a/python/rotational-cipher/rotational_cipher_test.py b/python/rotational-cipher/rotational_cipher_test.py new file mode 100644 index 0000000..ca22735 --- /dev/null +++ b/python/rotational-cipher/rotational_cipher_test.py @@ -0,0 +1,44 @@ +# These tests are auto-generated with test data from: +# https://github.com/exercism/problem-specifications/tree/main/exercises/rotational-cipher/canonical-data.json +# File last updated on 2023-07-19 + +import unittest + +from rotational_cipher import ( + rotate, +) + + +class RotationalCipherTest(unittest.TestCase): + def test_rotate_a_by_0_same_output_as_input(self): + self.assertEqual(rotate("a", 0), "a") + + def test_rotate_a_by_1(self): + self.assertEqual(rotate("a", 1), "b") + + def test_rotate_a_by_26_same_output_as_input(self): + self.assertEqual(rotate("a", 26), "a") + + def test_rotate_m_by_13(self): + self.assertEqual(rotate("m", 13), "z") + + def test_rotate_n_by_13_with_wrap_around_alphabet(self): + self.assertEqual(rotate("n", 13), "a") + + def test_rotate_capital_letters(self): + self.assertEqual(rotate("OMG", 5), "TRL") + + def test_rotate_spaces(self): + self.assertEqual(rotate("O M G", 5), "T R L") + + def test_rotate_numbers(self): + self.assertEqual(rotate("Testing 1 2 3 testing", 4), "Xiwxmrk 1 2 3 xiwxmrk") + + def test_rotate_punctuation(self): + self.assertEqual(rotate("Let's eat, Grandma!", 21), "Gzo'n zvo, Bmviyhv!") + + def test_rotate_all_letters(self): + self.assertEqual( + rotate("The quick brown fox jumps over the lazy dog.", 13), + "Gur dhvpx oebja sbk whzcf bire gur ynml qbt.", + ) diff --git a/python/say/.exercism/config.json b/python/say/.exercism/config.json new file mode 100644 index 0000000..ec2336b --- /dev/null +++ b/python/say/.exercism/config.json @@ -0,0 +1,34 @@ +{ + "authors": [ + "behrtam" + ], + "contributors": [ + "AndrejTS", + "cmccandless", + "csabella", + "Dog", + "fortrieb", + "gabriellhrn", + "ikhadykin", + "mandel01", + "N-Parsons", + "pheanex", + "pranasziaukas", + "tqa236", + "tsamoglou" + ], + "files": { + "solution": [ + "say.py" + ], + "test": [ + "say_test.py" + ], + "example": [ + ".meta/example.py" + ] + }, + "blurb": "Given a number from 0 to 999,999,999,999, spell out that number in English.", + "source": "A variation on the JavaRanch CattleDrive, Assignment 4", + "source_url": "https://web.archive.org/web/20240907035912/https://coderanch.com/wiki/718804" +} diff --git a/python/say/.exercism/metadata.json b/python/say/.exercism/metadata.json new file mode 100644 index 0000000..b6324bd --- /dev/null +++ b/python/say/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"say","id":"e89bd649c9b44a949d63bb0d5e57d36b","url":"https://exercism.org/tracks/python/exercises/say","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/say/HELP.md b/python/say/HELP.md new file mode 100644 index 0000000..63721aa --- /dev/null +++ b/python/say/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Correr os testes + +Usamos o [pytest][pytest: Getting Started Guide] como executor de testes do nosso site. +Vais precisar de instalar o `pytest` na tua máquina de desenvolvimento se quiseres correr os testes do percurso Python localmente. +Também vais precisar de instalar os seguintes plugins do `pytest`: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Encontras informação mais detalhada no [guia de testes de Python][Python track tests page] do nosso site. + + +### Correr os testes + +Para correres os testes incluídos, navega até à pasta onde o exercício está guardado usando o `cd` no teu terminal (_substitui `<exercise-folder-location>` abaixo pelo teu caminho_). +Os ficheiros de teste terminam habitualmente em `_test.py` e são os mesmos testes que correm no site quando uma solução é submetida. + +Linux/MacOS +```bash +$ cd <path/to/exercise-folder-location> +``` + +Windows +```powershell +PS C:\Users\foobar> cd <path\to\exercise-folder-location> +``` + +<br> + +De seguida, corre o comando `pytest` no teu terminal, substituindo `<exercise_test.py>` pelo nome do ficheiro de teste: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task <exercise_test.py> +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task <exercise_test.py> +==================== 7 passed in 0.08s ==================== +``` + + +### Opções comuns +- `-o` : substitui o `pytest.ini` predefinido (_podes usar esta opção para evitar avisos de marcadores_) +- `-v` : ativa a saída detalhada. +- `-x` : para de correr os testes na primeira falha. +- `--ff` : corre as falhas do teste anterior antes de correr os outros casos de teste. + +Para opções adicionais, usa `python3 -m pytest -h` ou `py -m pytest -h`. + + +### Corrigir avisos + +Se não usares `pytest -o markers=task` ao invocar o `pytest`, podes receber um `PytestUnknownMarkWarning` nos testes que usam a nossa nova sintaxe: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +Para evitares escrever `pytest -o markers=task` em todos os testes que corres, podes usar um ficheiro de configuração `pytest.ini`. +Criámos um que podes descarregar a partir do nível de topo do diretório do percurso Python: [pytest.ini][pytest.ini]. + +Também podes criar o teu próprio ficheiro `pytest.ini` com o seguinte conteúdo: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Colocar o ficheiro `pytest.ini` no diretório _root_ ou _working_ dos teus exercícios do percurso Python regista os marcadores e faz parar os avisos. +Encontras mais informação sobre os marcadores do pytest na documentação do `pytest` sobre [marcar funções de teste][pytest: marking test functions with attributes] e na documentação do `pytest` sobre [trabalhar com marcadores personalizados][pytest: working with custom markers]. + +Encontras informação sobre como personalizar as configurações do pytest na documentação do `pytest` sobre [formatos de ficheiros de configuração][pytest: configuration file formats]. + + +### Estender o teu IDE ou editor de código + +Muitos IDEs e editores de código têm suporte integrado para usar o `pytest` e outras ferramentas de qualidade de código. +Podes encontrar algumas opções da comunidade na nossa [página de ferramentas do percurso Python][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submeter a tua solução + +Podes submeter a tua solução com o comando `exercism submit say.py`. +Este comando envia a tua solução para o site do Exercism e imprime o URL da página da solução. + +É possível submeter uma solução incompleta, o que te permite: + +- Ver como outras pessoas resolveram o exercício +- Pedir ajuda a um mentor + +## Precisas de ajuda? + +Se quiseres ajuda para resolver o exercício, consulta as seguintes páginas: + +- A [documentação do percurso Python](https://exercism.org/docs/tracks/python) +- A [categoria de programação do percurso Python no fórum](https://forum.exercism.org/c/programming/python) +- A [categoria de programação do Exercism no fórum](https://forum.exercism.org/c/programming/5) +- As [Perguntas Frequentes](https://exercism.org/docs/using/faqs) + +Se esses recursos não forem suficientes, podes submeter a tua solução (incompleta) para pedir mentoria. + +Abaixo encontras alguns recursos para obter ajuda, caso tenhas problemas: + +- [A PSF](https://www.python.org) aloja as transferências do Python, a documentação e recursos da comunidade. +- Os [Fóruns da Comunidade Python](https://discuss.python.org/) servem para obter ajuda, discutir PEPs, falar com os principais contribuidores do Python e muito mais. +- [A Comunidade do Exercism no Discord](https://exercism.org/r/discord) +- [Os Fóruns de Discussão da Comunidade do Exercism](https://forum.exercsim.org) +- A [Comunidade Python no Discord](https://pythondiscord.com/) é uma comunidade muito prestável e ativa. +- O [/r/learnpython/](https://www.reddit.com/r/learnpython/) é um subreddit pensado para quem está a aprender Python. +- O [#python no Libera.chat](https://www.python.org/community/irc/) é o sítio onde os programadores responsáveis pela linguagem se juntam e põem o trabalho em dia. +- Os [Fóruns da Comunidade Free Code Camp](https://forum.freecodecamp.org/) +- O [Pythontutor](http://pythontutor.com/) para percorrer pequenos excertos de código visualmente. + +Além disso, o [StackOverflow](http://stackoverflow.com/questions/tagged/python) é um bom sítio para procurar o teu problema ou a tua dúvida e ver se já foi respondida. +Se não foi, podes sempre [perguntar](https://stackoverflow.com/help/how-to-ask) ou [responder](https://stackoverflow.com/help/how-to-answer) à pergunta de outra pessoa. \ No newline at end of file diff --git a/python/say/README.md b/python/say/README.md new file mode 100644 index 0000000..6760494 --- /dev/null +++ b/python/say/README.md @@ -0,0 +1,66 @@ +# Diz + +Bem-vindo ao Diz no percurso Python do Exercism. +Se precisares de ajuda para correr os testes ou para submeter o teu código, consulta o `HELP.md`. + +## Introduction + +O teu amigo Yaʻqūb trabalha ao balcão da delicatessen mais movimentada da cidade, a cortar, a pesar e a embrulhar encomendas para uma fila infindável de clientes com fome. +Para as coisas não pararem, cada cliente tira uma senha numerada quando chega. + +Quando é altura de chamar a pessoa seguinte, o Yaʻqūb lê o número em voz alta, sempre por palavras completas em inglês, para garantir que toda a gente o ouve com clareza. + +## Instructions + +Dado um número, a tua tarefa é escrevê-lo por palavras em inglês, exatamente como o teu amigo o diria em voz alta. +Yaʻqūb espera usar números de 0 até 999 999 999 999. + +Exemplos: + +- 0 → zero +- 1 → one +- 12 → twelve +- 123 → one hundred twenty-three +- 1 234 → one thousand two hundred thirty-four + +## Mensagens de exceção + +Por vezes é necessário [lançar uma exceção](https://docs.python.org/3/tutorial/errors.html#raising-exceptions). Quando o fazes, deves incluir sempre uma **mensagem de erro significativa** que indique qual é a origem do erro. Isto torna o teu código mais legível e ajuda bastante na depuração. Nos casos em que sabes que a origem do erro será de um determinado tipo, podes optar por lançar um dos [tipos de erro incorporados](https://docs.python.org/3/library/exceptions.html#base-classes), mas deves continuar a incluir uma mensagem significativa. + +Este exercício em particular exige que uses a [instrução raise](https://docs.python.org/3/reference/simple_stmts.html#the-raise-statement) para "lançar" um `ValueError` se o valor de entrada de `say()` estiver fora do intervalo. Os testes só passam se fizeres `raise` da `exception` e incluíres uma mensagem com ela. + +Para lançar um `ValueError` com uma mensagem, escreve a mensagem como argumento do tipo `exception`: + +```python +# if the number is negative +raise ValueError("input out of range") + +# if the number is larger than 999,999,999,999 +raise ValueError("input out of range") +``` + +## Source + +### Created by + +- @behrtam + +### Contributed to by + +- @AndrejTS +- @cmccandless +- @csabella +- @Dog +- @fortrieb +- @gabriellhrn +- @ikhadykin +- @mandel01 +- @N-Parsons +- @pheanex +- @pranasziaukas +- @tqa236 +- @tsamoglou + +### Based on + +A variation on the JavaRanch CattleDrive, Assignment 4 - https://web.archive.org/web/20240907035912/https://coderanch.com/wiki/718804 \ No newline at end of file diff --git a/python/say/say.py b/python/say/say.py new file mode 100644 index 0000000..5b8901e --- /dev/null +++ b/python/say/say.py @@ -0,0 +1,4 @@ +def say(number): + output: str = "" + + return output diff --git a/python/say/say_test.py b/python/say/say_test.py new file mode 100644 index 0000000..1b9cbde --- /dev/null +++ b/python/say/say_test.py @@ -0,0 +1,85 @@ +# These tests are auto-generated with test data from: +# https://github.com/exercism/problem-specifications/tree/main/exercises/say/canonical-data.json +# File last updated on 2023-07-19 + +import unittest + +from say import ( + say, +) + + +class SayTest(unittest.TestCase): + def test_zero(self): + self.assertEqual(say(0), "zero") + + def test_one(self): + self.assertEqual(say(1), "one") + + def test_fourteen(self): + self.assertEqual(say(14), "fourteen") + + def test_twenty(self): + self.assertEqual(say(20), "twenty") + + def test_twenty_two(self): + self.assertEqual(say(22), "twenty-two") + + def test_thirty(self): + self.assertEqual(say(30), "thirty") + + def test_ninety_nine(self): + self.assertEqual(say(99), "ninety-nine") + + def test_one_hundred(self): + self.assertEqual(say(100), "one hundred") + + def test_one_hundred_twenty_three(self): + self.assertEqual(say(123), "one hundred twenty-three") + + def test_two_hundred(self): + self.assertEqual(say(200), "two hundred") + + def test_nine_hundred_ninety_nine(self): + self.assertEqual(say(999), "nine hundred ninety-nine") + + def test_one_thousand(self): + self.assertEqual(say(1000), "one thousand") + + def test_one_thousand_two_hundred_thirty_four(self): + self.assertEqual(say(1234), "one thousand two hundred thirty-four") + + def test_one_million(self): + self.assertEqual(say(1000000), "one million") + + def test_one_million_two_thousand_three_hundred_forty_five(self): + self.assertEqual( + say(1002345), "one million two thousand three hundred forty-five" + ) + + def test_one_billion(self): + self.assertEqual(say(1000000000), "one billion") + + def test_a_big_number(self): + self.assertEqual( + say(987654321123), + "nine hundred eighty-seven billion six hundred fifty-four million three hundred twenty-one thousand one hundred twenty-three", + ) + + def test_numbers_below_zero_are_out_of_range(self): + with self.assertRaises(ValueError) as err: + say(-1) + + self.assertEqual(type(err.exception), ValueError) + self.assertEqual(err.exception.args[0], "input out of range") + + def test_numbers_above_999_999_999_999_are_out_of_range(self): + with self.assertRaises(ValueError) as err: + say(1000000000000) + + self.assertEqual(type(err.exception), ValueError) + self.assertEqual(err.exception.args[0], "input out of range") + + # Additional tests for this track + def test_one_hundred_seventy(self): + self.assertEqual(say(170), "one hundred seventy") diff --git a/python/secret-handshake/.exercism/config.json b/python/secret-handshake/.exercism/config.json new file mode 100644 index 0000000..7972aa1 --- /dev/null +++ b/python/secret-handshake/.exercism/config.json @@ -0,0 +1,35 @@ +{ + "authors": [ + "betegelse" + ], + "contributors": [ + "behrtam", + "cmccandless", + "crsmi", + "Dog", + "Grociu", + "ikhadykin", + "kytrinyx", + "N-Parsons", + "pheanex", + "sjakobi", + "sjwarner-bp", + "subkrish", + "tqa236", + "yawpitch" + ], + "files": { + "solution": [ + "secret_handshake.py" + ], + "test": [ + "secret_handshake_test.py" + ], + "example": [ + ".meta/example.py" + ] + }, + "blurb": "Given a decimal number, convert it to the appropriate sequence of events for a secret handshake.", + "source": "Bert, in Mary Poppins", + "source_url": "https://www.imdb.com/title/tt0058331/quotes/?item=qt0437047" +} diff --git a/python/secret-handshake/.exercism/metadata.json b/python/secret-handshake/.exercism/metadata.json new file mode 100644 index 0000000..e21b195 --- /dev/null +++ b/python/secret-handshake/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"secret-handshake","id":"f1f23c6106f44f09b72e6154c72317d7","url":"https://exercism.org/tracks/python/exercises/secret-handshake","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/secret-handshake/HELP.md b/python/secret-handshake/HELP.md new file mode 100644 index 0000000..a2fef07 --- /dev/null +++ b/python/secret-handshake/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +<br> + +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit secret_handshake.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/secret-handshake/README.md b/python/secret-handshake/README.md new file mode 100644 index 0000000..fffc74c --- /dev/null +++ b/python/secret-handshake/README.md @@ -0,0 +1,95 @@ +# Secret Handshake + +Welcome to Secret Handshake on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Introduction + +You are starting a secret coding club with some friends and friends-of-friends. +Not everyone knows each other, so you and your friends have decided to create a secret handshake that you can use to recognize that someone is a member. +You don't want anyone who isn't in the know to be able to crack the code. + +You've designed the code so that one person says a number between 1 and 31, and the other person turns it into a series of actions. + +## Instructions + +Your task is to convert a number between 1 and 31 to a sequence of actions in the secret handshake. + +The sequence of actions is chosen by looking at the rightmost five digits of the number once it's been converted to binary. +Start at the right-most digit and move left. + +The actions for each number place are: + +```plaintext +00001 = wink +00010 = double blink +00100 = close your eyes +01000 = jump +10000 = Reverse the order of the operations in the secret handshake. +``` + +Let's use the number `9` as an example: + +- 9 in binary is `1001`. +- The digit that is farthest to the right is 1, so the first action is `wink`. +- Going left, the next digit is 0, so there is no double-blink. +- Going left again, the next digit is 0, so you leave your eyes open. +- Going left again, the next digit is 1, so you jump. + +That was the last digit, so the final code is: + +```plaintext +wink, jump +``` + +Given the number 26, which is `11010` in binary, we get the following actions: + +- double blink +- jump +- reverse actions + +The secret handshake for 26 is therefore: + +```plaintext +jump, double blink +``` + +~~~~exercism/note +If you aren't sure what binary is or how it works, check out [this binary tutorial][intro-to-binary]. + +[intro-to-binary]: https://medium.com/basecs/bits-bytes-building-with-binary-13cb4289aafa +~~~~ + +To keep things simple (and to let you focus on the important part of this exercise), your function will receive its inputs as binary strings: + +``` +>>> commands("00011") +["wink", "double blink"] +``` + +## Source + +### Created by + +- @betegelse + +### Contributed to by + +- @behrtam +- @cmccandless +- @crsmi +- @Dog +- @Grociu +- @ikhadykin +- @kytrinyx +- @N-Parsons +- @pheanex +- @sjakobi +- @sjwarner-bp +- @subkrish +- @tqa236 +- @yawpitch + +### Based on + +Bert, in Mary Poppins - https://www.imdb.com/title/tt0058331/quotes/?item=qt0437047 \ No newline at end of file diff --git a/python/secret-handshake/__pycache__/secret_handshake.cpython-313.pyc b/python/secret-handshake/__pycache__/secret_handshake.cpython-313.pyc new file mode 100644 index 0000000..56af9bb Binary files /dev/null and b/python/secret-handshake/__pycache__/secret_handshake.cpython-313.pyc differ diff --git a/python/secret-handshake/__pycache__/secret_handshake.cpython-314.pyc b/python/secret-handshake/__pycache__/secret_handshake.cpython-314.pyc new file mode 100644 index 0000000..36f7bc1 Binary files /dev/null and b/python/secret-handshake/__pycache__/secret_handshake.cpython-314.pyc differ diff --git a/python/secret-handshake/__pycache__/secret_handshake_test.cpython-313-pytest-8.3.4.pyc b/python/secret-handshake/__pycache__/secret_handshake_test.cpython-313-pytest-8.3.4.pyc new file mode 100644 index 0000000..5f6249c Binary files /dev/null and b/python/secret-handshake/__pycache__/secret_handshake_test.cpython-313-pytest-8.3.4.pyc differ diff --git a/python/secret-handshake/__pycache__/secret_handshake_test.cpython-314-pytest-9.1.0.pyc b/python/secret-handshake/__pycache__/secret_handshake_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..83caedc Binary files /dev/null and b/python/secret-handshake/__pycache__/secret_handshake_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/secret-handshake/secret_handshake.py b/python/secret-handshake/secret_handshake.py new file mode 100644 index 0000000..f8d7015 --- /dev/null +++ b/python/secret-handshake/secret_handshake.py @@ -0,0 +1,24 @@ +def commands(binary_str): + list_of_commands: list = [ + 0, + "jump", + "close your eyes", + "double blink", + "wink", + ] + order_of_commands: list = [] + reverse_flag: bool = False + for index, code in enumerate(binary_str): + # if code is a '1', append the corresponded command to the order_of_commands + # unless the index is 0: in that case set the reverse_flag to True + # keep in mind i am searching for commands from left to right, so the order + # of commands is already reversed + if code == "1": + if index == 0: + reverse_flag = True + else: + order_of_commands.append(list_of_commands[index]) + # do i want to keep it reversed? + if not reverse_flag: + order_of_commands.reverse() + return order_of_commands diff --git a/python/secret-handshake/secret_handshake_test.py b/python/secret-handshake/secret_handshake_test.py new file mode 100644 index 0000000..544da4e --- /dev/null +++ b/python/secret-handshake/secret_handshake_test.py @@ -0,0 +1,48 @@ +# These tests are auto-generated with test data from: +# https://github.com/exercism/problem-specifications/tree/main/exercises/secret-handshake/canonical-data.json +# File last updated on 2023-07-19 + +import unittest + +from secret_handshake import ( + commands, +) + + +class SecretHandshakeTest(unittest.TestCase): + def test_wink_for_1(self): + self.assertEqual(commands("00001"), ["wink"]) + + def test_double_blink_for_10(self): + self.assertEqual(commands("00010"), ["double blink"]) + + def test_close_your_eyes_for_100(self): + self.assertEqual(commands("00100"), ["close your eyes"]) + + def test_jump_for_1000(self): + self.assertEqual(commands("01000"), ["jump"]) + + def test_combine_two_actions(self): + self.assertEqual(commands("00011"), ["wink", "double blink"]) + + def test_reverse_two_actions(self): + self.assertEqual(commands("10011"), ["double blink", "wink"]) + + def test_reversing_one_action_gives_the_same_action(self): + self.assertEqual(commands("11000"), ["jump"]) + + def test_reversing_no_actions_still_gives_no_actions(self): + self.assertEqual(commands("10000"), []) + + def test_all_possible_actions(self): + self.assertEqual( + commands("01111"), ["wink", "double blink", "close your eyes", "jump"] + ) + + def test_reverse_all_possible_actions(self): + self.assertEqual( + commands("11111"), ["jump", "close your eyes", "double blink", "wink"] + ) + + def test_do_nothing_for_zero(self): + self.assertEqual(commands("00000"), []) diff --git a/python/space-age/.exercism/config.json b/python/space-age/.exercism/config.json new file mode 100644 index 0000000..2c6189d --- /dev/null +++ b/python/space-age/.exercism/config.json @@ -0,0 +1,34 @@ +{ + "authors": [], + "contributors": [ + "abhijitparida", + "behrtam", + "cmccandless", + "crsmi", + "Dog", + "gabriel376", + "gabriellhrn", + "ikhadykin", + "kytrinyx", + "lowks", + "N-Parsons", + "pheanex", + "sjakobi", + "tqa236", + "AndrewLawendy" + ], + "files": { + "solution": [ + "space_age.py" + ], + "test": [ + "space_age_test.py" + ], + "example": [ + ".meta/example.py" + ] + }, + "blurb": "Given an age in seconds, calculate how old someone is in terms of a given planet's solar years.", + "source": "Partially inspired by Chapter 1 in Chris Pine's online Learn to Program tutorial.", + "source_url": "https://pine.fm/LearnToProgram/?Chapter=01" +} diff --git a/python/space-age/.exercism/metadata.json b/python/space-age/.exercism/metadata.json new file mode 100644 index 0000000..3e77ca2 --- /dev/null +++ b/python/space-age/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"space-age","id":"4681f2f4a1e34ed3a75ca3766a3bcecb","url":"https://exercism.org/tracks/python/exercises/space-age","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/space-age/HELP.md b/python/space-age/HELP.md new file mode 100644 index 0000000..737d061 --- /dev/null +++ b/python/space-age/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +<br> + +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit space_age.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/space-age/README.md b/python/space-age/README.md new file mode 100644 index 0000000..74f831c --- /dev/null +++ b/python/space-age/README.md @@ -0,0 +1,103 @@ +# Space Age + +Welcome to Space Age on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Introduction + +The year is 2525 and you've just embarked on a journey to visit all planets in the Solar System (Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus and Neptune). +The first stop is Mercury, where customs require you to fill out a form (bureaucracy is apparently _not_ Earth-specific). +As you hand over the form to the customs officer, they scrutinize it and frown. +"Do you _really_ expect me to believe you're just 50 years old? +You must be closer to 200 years old!" + +Amused, you wait for the customs officer to start laughing, but they appear to be dead serious. +You realize that you've entered your age in _Earth years_, but the officer expected it in _Mercury years_! +As Mercury's orbital period around the sun is significantly shorter than Earth, you're actually a lot older in Mercury years. +After some quick calculations, you're able to provide your age in Mercury Years. +The customs officer smiles, satisfied, and waves you through. +You make a mental note to pre-calculate your planet-specific age _before_ future customs checks, to avoid such mix-ups. + +~~~~exercism/note +If you're wondering why Pluto didn't make the cut, go watch [this YouTube video][pluto-video]. + +[pluto-video]: https://www.youtube.com/watch?v=Z_2gbGXzFbs +~~~~ + +## Instructions + +Given an age in seconds, calculate how old someone would be on a planet in our Solar System. + +One Earth year equals 365.25 Earth days, or 31,557,600 seconds. +If you were told someone was 1,000,000,000 seconds old, their age would be 31.69 Earth-years. + +For the other planets, you have to account for their orbital period in Earth Years: + +| Planet | Orbital period in Earth Years | +| ------- | ----------------------------- | +| Mercury | 0.2408467 | +| Venus | 0.61519726 | +| Earth | 1.0 | +| Mars | 1.8808158 | +| Jupiter | 11.862615 | +| Saturn | 29.447498 | +| Uranus | 84.016846 | +| Neptune | 164.79132 | + +~~~~exercism/note +The actual length of one complete orbit of the Earth around the sun is closer to 365.256 days (1 sidereal year). +The Gregorian calendar has, on average, 365.2425 days. +While not entirely accurate, 365.25 is the value used in this exercise. +See [Year on Wikipedia][year] for more ways to measure a year. + +[year]: https://en.wikipedia.org/wiki/Year#Summary +~~~~ + +For the Python track, this exercise asks you to create a `SpaceAge` _class_ (_[concept:python/classes]()_) that includes methods for all the planets of the solar system. +Methods should follow the naming convention `on_<planet name>`. + +Each method should `return` the age (_"on" that planet_) in years, rounded to two decimal places: + +```python +#creating an instance with one billion seconds, and calling .on_earth(). +>>> SpaceAge(1000000000).on_earth() + +#This is one billion seconds on Earth in years +31.69 +``` + +For more information on constructing and using classes, see: + +- [**A First Look at Classes**][first look at classes] from the Python documentation. +- [**A Word About names and Objects**][names and objects] from the Python documentation. +- [**Objects, values, and types**][objects, values and types] in the Python data model documentation. +- [**What is a Class?**][what is a class] from Trey Hunners Python Morsels website. + +[first look at classes]: https://docs.python.org/3/tutorial/classes.html#a-first-look-at-classes +[names and objects]: https://docs.python.org/3/tutorial/classes.html#a-word-about-names-and-objects +[objects, values and types]: https://docs.python.org/3/reference/datamodel.html#objects-values-and-types +[what is a class]: https://www.pythonmorsels.com/what-is-a-class/ + +## Source + +### Contributed to by + +- @abhijitparida +- @behrtam +- @cmccandless +- @crsmi +- @Dog +- @gabriel376 +- @gabriellhrn +- @ikhadykin +- @kytrinyx +- @lowks +- @N-Parsons +- @pheanex +- @sjakobi +- @tqa236 +- @AndrewLawendy + +### Based on + +Partially inspired by Chapter 1 in Chris Pine's online Learn to Program tutorial. - https://pine.fm/LearnToProgram/?Chapter=01 \ No newline at end of file diff --git a/python/space-age/__pycache__/space_age.cpython-313.pyc b/python/space-age/__pycache__/space_age.cpython-313.pyc new file mode 100644 index 0000000..5079b65 Binary files /dev/null and b/python/space-age/__pycache__/space_age.cpython-313.pyc differ diff --git a/python/space-age/__pycache__/space_age_test.cpython-313-pytest-8.3.5.pyc b/python/space-age/__pycache__/space_age_test.cpython-313-pytest-8.3.5.pyc new file mode 100644 index 0000000..6b18516 Binary files /dev/null and b/python/space-age/__pycache__/space_age_test.cpython-313-pytest-8.3.5.pyc differ diff --git a/python/space-age/__pycache__/space_age_test.cpython-314-pytest-9.1.0.pyc b/python/space-age/__pycache__/space_age_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..2dff7c9 Binary files /dev/null and b/python/space-age/__pycache__/space_age_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/space-age/space_age.py b/python/space-age/space_age.py new file mode 100644 index 0000000..3d6a69e --- /dev/null +++ b/python/space-age/space_age.py @@ -0,0 +1,46 @@ +class SpaceAge: + def __init__(self, seconds: int): + self.age_in_seconds: int = seconds + self.precision: int = 2 + self.seconds_earth_years: int = int(365.25 * 24 * 60 * 60) + + def on_earth(self) -> float: + return round( + self.age_in_seconds / + (self.seconds_earth_years) / 1, self.precision + ) + + def on_mercury(self): + return round( + self.age_in_seconds / self.seconds_earth_years / 0.2408467, self.precision + ) + + def on_venus(self): + return round( + self.age_in_seconds / self.seconds_earth_years / 0.61519726, self.precision + ) + + def on_mars(self): + return round( + self.age_in_seconds / self.seconds_earth_years / 1.8808158, self.precision + ) + + def on_jupiter(self): + return round( + self.age_in_seconds / self.seconds_earth_years / 11.862615, self.precision + ) + + def on_saturn(self): + return round( + self.age_in_seconds / self.seconds_earth_years / 29.447498, self.precision + ) + + def on_uranus(self): + retur round( + self.age_in_seconds / self.seconds_earth_years / 84.016846, self.precision + ) + + def on_neptune(self): + return round( + self.age_in_seconds / self.seconds_earth_years / 164.79132, self.precision + ) diff --git a/python/space-age/space_age_test.py b/python/space-age/space_age_test.py new file mode 100644 index 0000000..ddde365 --- /dev/null +++ b/python/space-age/space_age_test.py @@ -0,0 +1,35 @@ +# These tests are auto-generated with test data from: +# https://github.com/exercism/problem-specifications/tree/main/exercises/space-age/canonical-data.json +# File last updated on 2023-07-19 + +import unittest + +from space_age import ( + SpaceAge, +) + + +class SpaceAgeTest(unittest.TestCase): + def test_age_on_earth(self): + self.assertEqual(SpaceAge(1000000000).on_earth(), 31.69) + + def test_age_on_mercury(self): + self.assertEqual(SpaceAge(2134835688).on_mercury(), 280.88) + + def test_age_on_venus(self): + self.assertEqual(SpaceAge(189839836).on_venus(), 9.78) + + def test_age_on_mars(self): + self.assertEqual(SpaceAge(2129871239).on_mars(), 35.88) + + def test_age_on_jupiter(self): + self.assertEqual(SpaceAge(901876382).on_jupiter(), 2.41) + + def test_age_on_saturn(self): + self.assertEqual(SpaceAge(2000000000).on_saturn(), 2.15) + + def test_age_on_uranus(self): + self.assertEqual(SpaceAge(1210123456).on_uranus(), 0.46) + + def test_age_on_neptune(self): + self.assertEqual(SpaceAge(1821023456).on_neptune(), 0.35) diff --git a/python/square-root/.exercism/config.json b/python/square-root/.exercism/config.json new file mode 100644 index 0000000..b1b9630 --- /dev/null +++ b/python/square-root/.exercism/config.json @@ -0,0 +1,21 @@ +{ + "authors": [ + "meatball133", + "Bethanyg" + ], + "contributors": [], + "files": { + "solution": [ + "square_root.py" + ], + "test": [ + "square_root_test.py" + ], + "example": [ + ".meta/example.py" + ] + }, + "blurb": "Given a natural radicand, return its square root.", + "source": "wolf99", + "source_url": "https://github.com/exercism/problem-specifications/pull/1582" +} diff --git a/python/square-root/.exercism/metadata.json b/python/square-root/.exercism/metadata.json new file mode 100644 index 0000000..34c258a --- /dev/null +++ b/python/square-root/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"square-root","id":"34bc21bfe68d44bcbc14da478ae7c161","url":"https://exercism.org/tracks/python/exercises/square-root","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/square-root/HELP.md b/python/square-root/HELP.md new file mode 100644 index 0000000..1659db8 --- /dev/null +++ b/python/square-root/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +<br> + +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit square_root.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/square-root/README.md b/python/square-root/README.md new file mode 100644 index 0000000..f65bb95 --- /dev/null +++ b/python/square-root/README.md @@ -0,0 +1,60 @@ +# Square Root + +Welcome to Square Root on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Introduction + +We are launching a deep space exploration rocket and we need a way to make sure the navigation system stays on target. + +As the first step in our calculation, we take a target number and find its square root (that is, the number that when multiplied by itself equals the target number). + +The journey will be very long. +To make the batteries last as long as possible, we had to make our rocket's onboard computer very power efficient. +Unfortunately that means that we can't rely on fancy math libraries and functions, as they use more power. +Instead we want to implement our own square root calculation. + +## Instructions + +Your task is to calculate the square root of a given number. + +- Try to avoid using the pre-existing math libraries of your language. +- As input you'll be given a positive whole number, i.e. 1, 2, 3, 4… +- You are only required to handle cases where the result is a positive whole number. + +Some potential approaches: + +- Linear or binary search for a number that gives the input number when squared. +- Successive approximation using Newton's or Heron's method. +- Calculating one digit at a time or one bit at a time. + +You can check out the Wikipedia pages on [integer square root][integer-square-root] and [methods of computing square roots][computing-square-roots] to help with choosing a method of calculation. + +[integer-square-root]: https://en.wikipedia.org/wiki/Integer_square_root +[computing-square-roots]: https://en.wikipedia.org/wiki/Methods_of_computing_square_roots + +## How this Exercise is Structured in Python + + +Python offers a wealth of mathematical functions in the form of the [math module][math-module] and built-ins such as the exponentiation operator `**`, [`pow()`][pow] and [`sum()`][sum]. +However, we'd like you to consider the challenge of solving this exercise without those built-ins or modules. + +While there is a mathematical formula that will find the square root of _any_ number, we have gone the route of having only [natural numbers][nautral-number] (positive integers) as solutions. +It is possible to compute the square root of any natural number using only natural numbers in the computation. + + +[math-module]: https://docs.python.org/3/library/math.html +[pow]: https://docs.python.org/3/library/functions.html#pow +[sum]: https://docs.python.org/3/library/functions.html#sum +[nautral-number]: https://en.wikipedia.org/wiki/Natural_number + +## Source + +### Created by + +- @meatball133 +- @Bethanyg + +### Based on + +wolf99 - https://github.com/exercism/problem-specifications/pull/1582 \ No newline at end of file diff --git a/python/square-root/__pycache__/square_root.cpython-313.pyc b/python/square-root/__pycache__/square_root.cpython-313.pyc new file mode 100644 index 0000000..e2d71ec Binary files /dev/null and b/python/square-root/__pycache__/square_root.cpython-313.pyc differ diff --git a/python/square-root/__pycache__/square_root.cpython-314.pyc b/python/square-root/__pycache__/square_root.cpython-314.pyc new file mode 100644 index 0000000..c2bcc85 Binary files /dev/null and b/python/square-root/__pycache__/square_root.cpython-314.pyc differ diff --git a/python/square-root/__pycache__/square_root_test.cpython-313-pytest-8.3.4.pyc b/python/square-root/__pycache__/square_root_test.cpython-313-pytest-8.3.4.pyc new file mode 100644 index 0000000..418c919 Binary files /dev/null and b/python/square-root/__pycache__/square_root_test.cpython-313-pytest-8.3.4.pyc differ diff --git a/python/square-root/__pycache__/square_root_test.cpython-314-pytest-9.1.0.pyc b/python/square-root/__pycache__/square_root_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..876759a Binary files /dev/null and b/python/square-root/__pycache__/square_root_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/square-root/square_root.py b/python/square-root/square_root.py new file mode 100644 index 0000000..13c7bb3 --- /dev/null +++ b/python/square-root/square_root.py @@ -0,0 +1,7 @@ +def square_root(number): + if number <= 0: + raise ValueError("only accept positive integers") + for root in range(1, number + 1): + if (root * root) == number: + return root + return 0 diff --git a/python/square-root/square_root_test.py b/python/square-root/square_root_test.py new file mode 100644 index 0000000..8f94940 --- /dev/null +++ b/python/square-root/square_root_test.py @@ -0,0 +1,29 @@ +# These tests are auto-generated with test data from: +# https://github.com/exercism/problem-specifications/tree/main/exercises/square-root/canonical-data.json +# File last updated on 2023-07-19 + +import unittest + +from square_root import ( + square_root, +) + + +class SquareRootTest(unittest.TestCase): + def test_root_of_1(self): + self.assertEqual(square_root(1), 1) + + def test_root_of_4(self): + self.assertEqual(square_root(4), 2) + + def test_root_of_25(self): + self.assertEqual(square_root(25), 5) + + def test_root_of_81(self): + self.assertEqual(square_root(81), 9) + + def test_root_of_196(self): + self.assertEqual(square_root(196), 14) + + def test_root_of_65025(self): + self.assertEqual(square_root(65025), 255) diff --git a/python/sublist/.exercism/config.json b/python/sublist/.exercism/config.json new file mode 100644 index 0000000..f4aeb47 --- /dev/null +++ b/python/sublist/.exercism/config.json @@ -0,0 +1,34 @@ +{ + "authors": [ + "betegelse" + ], + "contributors": [ + "anunciado", + "behrtam", + "cmccandless", + "csabella", + "Dog", + "dvermd", + "Grociu", + "ikhadykin", + "kytrinyx", + "N-Parsons", + "patricksjackson", + "Peque", + "pheanex", + "sjakobi", + "tqa236" + ], + "files": { + "solution": [ + "sublist.py" + ], + "test": [ + "sublist_test.py" + ], + "example": [ + ".meta/example.py" + ] + }, + "blurb": "Write a function to determine if a list is a sublist of another list." +} diff --git a/python/sublist/.exercism/metadata.json b/python/sublist/.exercism/metadata.json new file mode 100644 index 0000000..6308818 --- /dev/null +++ b/python/sublist/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"sublist","id":"30eabe87f0e742059c8a8edf10db46d5","url":"https://exercism.org/tracks/python/exercises/sublist","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/sublist/HELP.md b/python/sublist/HELP.md new file mode 100644 index 0000000..28fae53 --- /dev/null +++ b/python/sublist/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +<br> + +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit sublist.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/sublist/README.md b/python/sublist/README.md new file mode 100644 index 0000000..09da0d5 --- /dev/null +++ b/python/sublist/README.md @@ -0,0 +1,54 @@ +# Sublist + +Welcome to Sublist on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Instructions + +Given any two lists `A` and `B`, determine if: + +- List `A` is equal to list `B`; or +- List `A` contains list `B` (`A` is a superlist of `B`); or +- List `A` is contained by list `B` (`A` is a sublist of `B`); or +- None of the above is true, thus lists `A` and `B` are unequal + +Specifically, list `A` is equal to list `B` if both lists have the same values in the same order. +List `A` is a superlist of `B` if `A` contains a contiguous sub-sequence of values equal to `B`. +List `A` is a sublist of `B` if `B` contains a contiguous sub-sequence of values equal to `A`. + +Examples: + +- If `A = []` and `B = []` (both lists are empty), then `A` and `B` are equal +- If `A = [1, 2, 3]` and `B = []`, then `A` is a superlist of `B` +- If `A = []` and `B = [1, 2, 3]`, then `A` is a sublist of `B` +- If `A = [1, 2, 3]` and `B = [1, 2, 3, 4, 5]`, then `A` is a sublist of `B` +- If `A = [3, 4, 5]` and `B = [1, 2, 3, 4, 5]`, then `A` is a sublist of `B` +- If `A = [3, 4]` and `B = [1, 2, 3, 4, 5]`, then `A` is a sublist of `B` +- If `A = [1, 2, 3]` and `B = [1, 2, 3]`, then `A` and `B` are equal +- If `A = [1, 2, 3, 4, 5]` and `B = [2, 3, 4]`, then `A` is a superlist of `B` +- If `A = [1, 2, 4]` and `B = [1, 2, 3, 4, 5]`, then `A` and `B` are unequal +- If `A = [1, 2, 3]` and `B = [1, 3, 2]`, then `A` and `B` are unequal + +## Source + +### Created by + +- @betegelse + +### Contributed to by + +- @anunciado +- @behrtam +- @cmccandless +- @csabella +- @Dog +- @dvermd +- @Grociu +- @ikhadykin +- @kytrinyx +- @N-Parsons +- @patricksjackson +- @Peque +- @pheanex +- @sjakobi +- @tqa236 \ No newline at end of file diff --git a/python/sublist/__pycache__/sublist.cpython-313.pyc b/python/sublist/__pycache__/sublist.cpython-313.pyc new file mode 100644 index 0000000..e80296a Binary files /dev/null and b/python/sublist/__pycache__/sublist.cpython-313.pyc differ diff --git a/python/sublist/__pycache__/sublist.cpython-314.pyc b/python/sublist/__pycache__/sublist.cpython-314.pyc new file mode 100644 index 0000000..87d5794 Binary files /dev/null and b/python/sublist/__pycache__/sublist.cpython-314.pyc differ diff --git a/python/sublist/__pycache__/sublist_test.cpython-313-pytest-8.3.5.pyc b/python/sublist/__pycache__/sublist_test.cpython-313-pytest-8.3.5.pyc new file mode 100644 index 0000000..89539e8 Binary files /dev/null and b/python/sublist/__pycache__/sublist_test.cpython-313-pytest-8.3.5.pyc differ diff --git a/python/sublist/__pycache__/sublist_test.cpython-314-pytest-9.1.0.pyc b/python/sublist/__pycache__/sublist_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..7a8dbd1 Binary files /dev/null and b/python/sublist/__pycache__/sublist_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/sublist/sublist.py b/python/sublist/sublist.py new file mode 100644 index 0000000..90a090b --- /dev/null +++ b/python/sublist/sublist.py @@ -0,0 +1,40 @@ +""" +This exercise stub and the test suite contain several enumerated constants. + +Enumerated constants can be done with a NAME assigned to an arbitrary, +but unique value. An integer is traditionally used because it’s memory +efficient. +It is a common practice to export both constants and functions that work with +those constants (ex. the constants in the os, subprocess and re modules). + +You can learn more here: https://en.wikipedia.org/wiki/Enumerated_type +""" + +# Possible sublist categories. +# Change the values as you see fit. +SUBLIST = 1 +SUPERLIST = 2 +EQUAL = 3 +UNEQUAL = 4 + + +def sublist(list_one: list, list_two: list): + # test for equality of lists + if list_one == list_two: + return EQUAL + # test for list_one is a sublist of list_two + if len(list_one) < len(list_two): + if any( + list_two[i : i + len(list_one)] == list_one + for i in range(len(list_two) - len(list_one) + 1) + ): + return SUBLIST + # test for list_one is a superlist of list_two + if len(list_one) > len(list_two): + if any( + list_one[i : i + len(list_two)] == list_two + for i in range(len(list_one) - len(list_two) + 1) + ): + return SUPERLIST + # previous tests failed, so lists are UNEQUAL + return UNEQUAL diff --git a/python/sublist/sublist_test.py b/python/sublist/sublist_test.py new file mode 100644 index 0000000..af9a779 --- /dev/null +++ b/python/sublist/sublist_test.py @@ -0,0 +1,90 @@ +# These tests are auto-generated with test data from: +# https://github.com/exercism/problem-specifications/tree/main/exercises/sublist/canonical-data.json +# File last updated on 2023-07-19 + +import unittest + +from sublist import ( + sublist, + SUBLIST, + SUPERLIST, + EQUAL, + UNEQUAL, +) + + +class SublistTest(unittest.TestCase): + def test_empty_lists(self): + self.assertEqual(sublist([], []), EQUAL) + + def test_empty_list_within_non_empty_list(self): + self.assertEqual(sublist([], [1, 2, 3]), SUBLIST) + + def test_non_empty_list_contains_empty_list(self): + self.assertEqual(sublist([1, 2, 3], []), SUPERLIST) + + def test_list_equals_itself(self): + self.assertEqual(sublist([1, 2, 3], [1, 2, 3]), EQUAL) + + def test_different_lists(self): + self.assertEqual(sublist([1, 2, 3], [2, 3, 4]), UNEQUAL) + + def test_false_start(self): + self.assertEqual(sublist([1, 2, 5], [0, 1, 2, 3, 1, 2, 5, 6]), SUBLIST) + + def test_consecutive(self): + self.assertEqual(sublist([1, 1, 2], [0, 1, 1, 1, 2, 1, 2]), SUBLIST) + + def test_sublist_at_start(self): + self.assertEqual(sublist([0, 1, 2], [0, 1, 2, 3, 4, 5]), SUBLIST) + + def test_sublist_in_middle(self): + self.assertEqual(sublist([2, 3, 4], [0, 1, 2, 3, 4, 5]), SUBLIST) + + def test_sublist_at_end(self): + self.assertEqual(sublist([3, 4, 5], [0, 1, 2, 3, 4, 5]), SUBLIST) + + def test_at_start_of_superlist(self): + self.assertEqual(sublist([0, 1, 2, 3, 4, 5], [0, 1, 2]), SUPERLIST) + + def test_in_middle_of_superlist(self): + self.assertEqual(sublist([0, 1, 2, 3, 4, 5], [2, 3]), SUPERLIST) + + def test_at_end_of_superlist(self): + self.assertEqual(sublist([0, 1, 2, 3, 4, 5], [3, 4, 5]), SUPERLIST) + + def test_first_list_missing_element_from_second_list(self): + self.assertEqual(sublist([1, 3], [1, 2, 3]), UNEQUAL) + + def test_second_list_missing_element_from_first_list(self): + self.assertEqual(sublist([1, 2, 3], [1, 3]), UNEQUAL) + + def test_first_list_missing_additional_digits_from_second_list(self): + self.assertEqual(sublist([1, 2], [1, 22]), UNEQUAL) + + def test_order_matters_to_a_list(self): + self.assertEqual(sublist([1, 2, 3], [3, 2, 1]), UNEQUAL) + + def test_same_digits_but_different_numbers(self): + self.assertEqual(sublist([1, 0, 1], [10, 1]), UNEQUAL) + + # Additional tests for this track + def test_unique_return_values(self): + self.assertEqual(len(set([SUBLIST, SUPERLIST, EQUAL, UNEQUAL])), 4) + + def test_inner_spaces(self): + self.assertEqual(sublist(["a c"], ["a", "c"]), UNEQUAL) + + def test_large_lists(self): + self.assertEqual( + sublist( + list(range(1000)) * 1000 + list(range(1000, 1100)), + list(range(900, 1050)), + ), + SUPERLIST, + ) + + def test_spread_sublist(self): + self.assertEqual( + sublist(list(range(3, 200, 3)), list(range(15, 200, 15))), UNEQUAL + ) diff --git a/python/sum-of-multiples/.exercism/config.json b/python/sum-of-multiples/.exercism/config.json new file mode 100644 index 0000000..cc5f1ce --- /dev/null +++ b/python/sum-of-multiples/.exercism/config.json @@ -0,0 +1,36 @@ +{ + "authors": [ + "sjakobi" + ], + "contributors": [ + "ackerleytng", + "behrtam", + "bsoyka", + "cmccandless", + "Dog", + "etmoore", + "GascaK", + "ikhadykin", + "julianandrews", + "kotp", + "kytrinyx", + "lekum", + "N-Parsons", + "pheanex", + "tqa236" + ], + "files": { + "solution": [ + "sum_of_multiples.py" + ], + "test": [ + "sum_of_multiples_test.py" + ], + "example": [ + ".meta/example.py" + ] + }, + "blurb": "Given a number, find the sum of all the multiples of particular numbers up to but not including that number.", + "source": "A variation on Problem 1 at Project Euler", + "source_url": "https://projecteuler.net/problem=1" +} diff --git a/python/sum-of-multiples/.exercism/metadata.json b/python/sum-of-multiples/.exercism/metadata.json new file mode 100644 index 0000000..d617906 --- /dev/null +++ b/python/sum-of-multiples/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"sum-of-multiples","id":"391288cf3f374490a713bc5193562262","url":"https://exercism.org/tracks/python/exercises/sum-of-multiples","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/sum-of-multiples/HELP.md b/python/sum-of-multiples/HELP.md new file mode 100644 index 0000000..d453775 --- /dev/null +++ b/python/sum-of-multiples/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +<br> + +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit sum_of_multiples.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/sum-of-multiples/README.md b/python/sum-of-multiples/README.md new file mode 100644 index 0000000..3727b9a --- /dev/null +++ b/python/sum-of-multiples/README.md @@ -0,0 +1,74 @@ +# Sum of Multiples + +Welcome to Sum of Multiples on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Introduction + +You work for a company that makes an online, fantasy-survival game. + +When a player finishes a level, they are awarded energy points. +The amount of energy awarded depends on which magical items the player found while exploring that level. + +## Instructions + +Your task is to write the code that calculates the energy points that get awarded to players when they complete a level. + +The points awarded depend on two things: + +- The level (a number) that the player completed. +- The base value of each magical item collected by the player during that level. + +The energy points are awarded according to the following rules: + +1. For each magical item, take the base value and find all the multiples of that value that are less than the level number. +2. Combine the sets of numbers. +3. Remove any duplicates. +4. Calculate the sum of all the numbers that are left. + +Let's look at an example: + +**The player completed level 20 and found two magical items with base values of 3 and 5.** + +To calculate the energy points earned by the player, we need to find all the unique multiples of these base values that are less than level 20. + +- Multiples of 3 less than 20: `{3, 6, 9, 12, 15, 18}` +- Multiples of 5 less than 20: `{5, 10, 15}` +- Combine the sets and remove duplicates: `{3, 5, 6, 9, 10, 12, 15, 18}` +- Sum the unique multiples: `3 + 5 + 6 + 9 + 10 + 12 + 15 + 18 = 78` +- Therefore, the player earns **78** energy points for completing level 20 and finding the two magical items with base values of 3 and 5. + +You can make the following assumptions about the inputs to the +`sum_of_multiples` function: +* All input numbers are non-negative `int`s, i.e. natural numbers +including zero. +* A list of factors must be given, and its elements are unique +and sorted in ascending order. + +## Source + +### Created by + +- @sjakobi + +### Contributed to by + +- @ackerleytng +- @behrtam +- @bsoyka +- @cmccandless +- @Dog +- @etmoore +- @GascaK +- @ikhadykin +- @julianandrews +- @kotp +- @kytrinyx +- @lekum +- @N-Parsons +- @pheanex +- @tqa236 + +### Based on + +A variation on Problem 1 at Project Euler - https://projecteuler.net/problem=1 \ No newline at end of file diff --git a/python/sum-of-multiples/__pycache__/sum_of_multiples.cpython-313.pyc b/python/sum-of-multiples/__pycache__/sum_of_multiples.cpython-313.pyc new file mode 100644 index 0000000..c830aa4 Binary files /dev/null and b/python/sum-of-multiples/__pycache__/sum_of_multiples.cpython-313.pyc differ diff --git a/python/sum-of-multiples/__pycache__/sum_of_multiples.cpython-314.pyc b/python/sum-of-multiples/__pycache__/sum_of_multiples.cpython-314.pyc new file mode 100644 index 0000000..9cc3f1a Binary files /dev/null and b/python/sum-of-multiples/__pycache__/sum_of_multiples.cpython-314.pyc differ diff --git a/python/sum-of-multiples/__pycache__/sum_of_multiples_test.cpython-313-pytest-8.3.5.pyc b/python/sum-of-multiples/__pycache__/sum_of_multiples_test.cpython-313-pytest-8.3.5.pyc new file mode 100644 index 0000000..5bff691 Binary files /dev/null and b/python/sum-of-multiples/__pycache__/sum_of_multiples_test.cpython-313-pytest-8.3.5.pyc differ diff --git a/python/sum-of-multiples/__pycache__/sum_of_multiples_test.cpython-314-pytest-9.1.0.pyc b/python/sum-of-multiples/__pycache__/sum_of_multiples_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..9aed842 Binary files /dev/null and b/python/sum-of-multiples/__pycache__/sum_of_multiples_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/sum-of-multiples/sum_of_multiples.py b/python/sum-of-multiples/sum_of_multiples.py new file mode 100644 index 0000000..934821a --- /dev/null +++ b/python/sum-of-multiples/sum_of_multiples.py @@ -0,0 +1,14 @@ +def sum_of_multiples(limit: int, multiples: list) -> int: + set_of_multiples: set = set() + sum: int = 0 + # search which level is multiple of 'multiple' and add them to the set + for factor in multiples: + for level in range(limit): + if factor == 0: + continue + if level % factor == 0: + set_of_multiples.add(level) + # sum the items on the set + for item in set_of_multiples: + sum += item + return sum diff --git a/python/sum-of-multiples/sum_of_multiples_test.py b/python/sum-of-multiples/sum_of_multiples_test.py new file mode 100644 index 0000000..0057ee7 --- /dev/null +++ b/python/sum-of-multiples/sum_of_multiples_test.py @@ -0,0 +1,61 @@ +# These tests are auto-generated with test data from: +# https://github.com/exercism/problem-specifications/tree/main/exercises/sum-of-multiples/canonical-data.json +# File last updated on 2023-07-19 + +import unittest + +from sum_of_multiples import ( + sum_of_multiples, +) + + +class SumOfMultiplesTest(unittest.TestCase): + def test_no_multiples_within_limit(self): + self.assertEqual(sum_of_multiples(1, [3, 5]), 0) + + def test_one_factor_has_multiples_within_limit(self): + self.assertEqual(sum_of_multiples(4, [3, 5]), 3) + + def test_more_than_one_multiple_within_limit(self): + self.assertEqual(sum_of_multiples(7, [3]), 9) + + def test_more_than_one_factor_with_multiples_within_limit(self): + self.assertEqual(sum_of_multiples(10, [3, 5]), 23) + + def test_each_multiple_is_only_counted_once(self): + self.assertEqual(sum_of_multiples(100, [3, 5]), 2318) + + def test_a_much_larger_limit(self): + self.assertEqual(sum_of_multiples(1000, [3, 5]), 233168) + + def test_three_factors(self): + self.assertEqual(sum_of_multiples(20, [7, 13, 17]), 51) + + def test_factors_not_relatively_prime(self): + self.assertEqual(sum_of_multiples(15, [4, 6]), 30) + + def test_some_pairs_of_factors_relatively_prime_and_some_not(self): + self.assertEqual(sum_of_multiples(150, [5, 6, 8]), 4419) + + def test_one_factor_is_a_multiple_of_another(self): + self.assertEqual(sum_of_multiples(51, [5, 25]), 275) + + def test_much_larger_factors(self): + self.assertEqual(sum_of_multiples(10000, [43, 47]), 2203160) + + def test_all_numbers_are_multiples_of_1(self): + self.assertEqual(sum_of_multiples(100, [1]), 4950) + + def test_no_factors_means_an_empty_sum(self): + self.assertEqual(sum_of_multiples(10000, []), 0) + + def test_the_only_multiple_of_0_is_0(self): + self.assertEqual(sum_of_multiples(1, [0]), 0) + + def test_the_factor_0_does_not_affect_the_sum_of_multiples_of_other_factors(self): + self.assertEqual(sum_of_multiples(4, [3, 0]), 3) + + def test_solutions_using_include_exclude_must_extend_to_cardinality_greater_than_3( + self, + ): + self.assertEqual(sum_of_multiples(10000, [2, 3, 5, 7, 11]), 39614537) diff --git a/python/tisbury-treasure-hunt/.exercism/config.json b/python/tisbury-treasure-hunt/.exercism/config.json new file mode 100644 index 0000000..6dba773 --- /dev/null +++ b/python/tisbury-treasure-hunt/.exercism/config.json @@ -0,0 +1,18 @@ +{ + "authors": [ + "BethanyG" + ], + "files": { + "solution": [ + "tuples.py" + ], + "test": [ + "tuples_test.py" + ], + "exemplar": [ + ".meta/exemplar.py" + ] + }, + "icon": "tisbury-treasure-hunt", + "blurb": "Learn about tuples by helping out competitors in the Tisbury Treasure Hunt." +} diff --git a/python/tisbury-treasure-hunt/.exercism/metadata.json b/python/tisbury-treasure-hunt/.exercism/metadata.json new file mode 100644 index 0000000..e6f127b --- /dev/null +++ b/python/tisbury-treasure-hunt/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"tisbury-treasure-hunt","id":"7781209d79994c8aad3a7128f6e4115d","url":"https://exercism.org/tracks/python/exercises/tisbury-treasure-hunt","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/tisbury-treasure-hunt/HELP.md b/python/tisbury-treasure-hunt/HELP.md new file mode 100644 index 0000000..25eaac5 --- /dev/null +++ b/python/tisbury-treasure-hunt/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +<br> + +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit tuples.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/tisbury-treasure-hunt/HINTS.md b/python/tisbury-treasure-hunt/HINTS.md new file mode 100644 index 0000000..ff5aba5 --- /dev/null +++ b/python/tisbury-treasure-hunt/HINTS.md @@ -0,0 +1,49 @@ +# Hints + +## General + + +- [Tuples][tuples] are immutable [sequence Types][sequence types] that can contain any data type. +- Tuples are [iterable][iterable]. If you need indexes as well as values, use [`enumerate()`][enumerate] +- Elements within tuples can be accessed via [bracket notation][bracket notation], using a zero-based index from the left, or -1 from the right. Other [Common Sequence Operations][common sequence operations] can also be used when working with tuples. + +## 1. Extract coordinates + +- Remember: tuples allow access via _index_, using _brackets_. Indexes start from the left at zero. + +## 2. Format coordinates + +- Check [`class tuple`][class tuple] for more details on tuples. +- Check [`class str`][class str] for more details on strings. + +## 3. Match coordinates + +- What methods could be used here for for [testing membership][testing membership]?. +- Check [`class tuple`][class tuple] for more details on tuples. +- Could you re-use your `convert_coordinate()` function? + +## 4. Combine matched records + +- Remember that tuples support all [common sequence operations][common sequence operations]. +- Could you re-use your `compare_records()` function here? + +## 5. "Clean up" & make a report of all records + +- Remember: tuples are _immutable_, but the contents can be accessed via _index_ using _bracket notation_. +- Tuples don't have to use parentheses unless there is _ambiguity_. +- Python has multiple methods of string formatting. [`str.format()`][str.format] and [`f-strings`][f-strings] are two very common ones. +- There are multiple textual formatting options available via Pythons [`format specification mini-language`][format specification mini-language]. + + +[bracket notation]: https://stackoverflow.com/questions/30250282/whats-the-difference-between-the-square-bracket-and-dot-notations-in-python +[class str]: https://docs.python.org/3/library/stdtypes.html#text-sequence-type-str +[class tuple]: https://docs.python.org/3/library/stdtypes.html#tuple +[common sequence operations]: https://docs.python.org/3/library/stdtypes.html#common-sequence-operations +[enumerate]: https://docs.python.org/3/library/functions.html#enumerate +[f-strings]: https://docs.python.org/3/tutorial/inputoutput.html#formatted-string-literals +[format specification mini-language]: https://docs.python.org/3/library/string.html#format-specification-mini-language +[iterable]: https://docs.python.org/3/glossary.html#term-iterable +[sequence types]: https://docs.python.org/3/library/stdtypes.html#typesseq +[str.format]: https://docs.python.org/3/library/stdtypes.html#str.format +[testing membership]: https://docs.python.org/3/reference/expressions.html#membership-test-operations +[tuples]: https://docs.python.org/3/tutorial/datastructures.html#tuples-and-sequences \ No newline at end of file diff --git a/python/tisbury-treasure-hunt/README.md b/python/tisbury-treasure-hunt/README.md new file mode 100644 index 0000000..694172b --- /dev/null +++ b/python/tisbury-treasure-hunt/README.md @@ -0,0 +1,279 @@ +# Tisbury Treasure Hunt + +Welcome to Tisbury Treasure Hunt on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. +If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :) + +## Introduction + +In Python, a [tuple][tuple] is an _immutable_ collection of items in _sequence_. +Like most collections, `tuples` can hold any (or multiple) data type(s) -- including other `tuples`. +Tuples support all [common sequence operations][common sequence operations], but **do not** support [mutable sequence operations][mutable sequence operations]. + +The elements of a tuple can be iterated over using the `for item in <tuple>` construct. +If both element index and value are needed, `for index, item in enumerate(<tuple>)` can be used. +Like any sequence, elements within `tuples` can be accessed via _bracket notation_ using a `0-based index` number from the left or a `-1-based index` number from the right. +Tuples can also be copied in whole or in part using slice notation (_`<tuple>[<start>:<stop>:<step>]`_). + + +## Tuple Construction + +Tuples can be formed in multiple ways, using either the `tuple(<iterable>)` class constructor or the `tuple` literal declaration. + +### Using the `tuple()` constructor empty or with an _iterable_: + +```python +>>> no_elements = tuple() +() + +# The constructor *requires* an iterable, so single elements must be passed in a list or another tuple. +>>> one_element = tuple([16]) +(16,) +``` + +Strings are iterable, so using a single `str` as an argument to the `tuple()` constructor can have surprising results: + +```python +# String elements (characters) are iterated through and added to the tuple +>>> multiple_elements_string = tuple("Timbuktu") +('T', 'i', 'm', 'b', 'u', 'k', 't', 'u') +``` + +Single iterables have their elements added one by one: + +```python +>>> multiple_elements_list = tuple(["Parrot", "Bird", 334782]) +("Parrot", "Bird", 334782) + +>>> multiple_elements_set = tuple({2, 3, 5, 7, 11}) +(2,3,5,7,11) +``` + +#### Declaring a tuple as a _literal_ : + +Because the `tuple(<iterable>)` constructor only takes _iterables_ (or nothing) as arguments, it is much easier to create + a one-tuple via the literal method. + +```python +>>> no_elements = () +() + +>>> one_element = ("Guava",) +("Guava",) +``` + +Nested data structures can be included as `tuple` elements, including other `tuples`: + +```python +>>> nested_data_structures = ({"fish": "gold", "monkey": "brown", "parrot" : "grey"}, ("fish", "mammal", "bird")) +({"fish": "gold", "monkey": "brown", "parrot" : "grey"}, ("fish", "mammal", "bird")) + +>>> nested_data_structures_1 = (["fish", "gold", "monkey", "brown", "parrot", "grey"], ("fish", "mammal", "bird")) +(["fish", "gold", "monkey", "brown", "parrot", "grey"], ("fish", "mammal", "bird")) +``` + +## Tuple Concatenation + +Tuples can be concatenated using plus `+` operator, which unpacks each `tuple` creating a new, combined `tuple`. + +```python +>>> new_via_concatenate = ("George", 5) + ("cat", "Tabby") +("George", 5, "cat", "Tabby") + +#likewise, using the multiplication operator * is the equivalent of using + n times +>>> first_group = ("cat", "dog", "elephant") + +>>> multiplied_group = first_group * 3 +('cat', 'dog', 'elephant', 'cat', 'dog', 'elephant', 'cat', 'dog', 'elephant') +``` + +## Accessing Elements Inside a Tuple + +Elements within a `tuple` can be accessed via _bracket notation_ using a `0-based index` number from the left or a `-1-based index` number from the right. + +```python +student_info = ("Alyssa", "grade 3", "female", 8 ) + +#gender is at index 2 or index -2 +>>> student_gender = student_info[2] +'female' + +>>> student_gender = student_info[-2] +'female' + +#name is at index 0 or index -4 +>>> student_name = student_info[0] +Alyssa + +>>> student_name = student_info[-4] +Alyssa +``` + +## Iterating Over a Tuples Elements + +Elements inside a `tuple` can be _iterated over_ in a loop using `for item in <tuple>` syntax. +If both indexes and values are needed, `for index, item in enumerate(<tuple>)` can be used. + +```python +>>> student_info = ("Alyssa", "grade 3", "female", 8 ) +>>> for item in student_info: +... print(item) + +... +Alyssa +grade 3 +female +8 + +>>> for index, item in enumerate(student_info): +... print("Index is: " + str(index) + ", value is: " + str(item) +".") + +... +Index is: 0, value is: Alyssa. +Index is: 1, value is: grade 3. +Index is: 2, value is: female. +Index is: 3, value is: 8. +``` + +## Checking Membership in a Tuple + +The `in` operator can be used to check membership in a `tuple`. + +```python +>>> multiple_elements_list = tuple(["Parrot", "Bird", 334782]) +("Parrot", "Bird", 334782) + +>>> "Parrot" in multiple_elements_list +True +``` + +[common sequence operations]: https://docs.python.org/3/library/stdtypes.html#common-sequence-operations +[mutable sequence operations]: https://docs.python.org/3/library/stdtypes.html#mutable-sequence-types +[tuple]: https://docs.python.org/3/library/stdtypes.html#tuple + +## Instructions + +Azara and Rui are teammates competing in a pirate-themed treasure hunt. +One has a list of treasures with map coordinates, the other a list of location names with map coordinates. +They've also been given blank maps with a starting place marked YOU ARE HERE. + +<br> +<table> +<tr><th>Azara's List</th><th></th><th>Rui's List</th></tr> +<tr><td> + +| Treasure | Coordinates | +| --------------------------- | ----------- | +| Amethyst Octopus | 1F | +| Angry Monkey Figurine | 5B | +| Antique Glass Fishnet Float | 3D | +| Brass Spyglass | 4B | +| Carved Wooden Elephant | 8C | +| Crystal Crab | 6A | +| Glass Starfish | 6D | +| Model Ship in Large Bottle | 8A | +| Pirate Flag | 7F | +| Robot Parrot | 1C | +| Scrimshawed Whale Tooth | 2A | +| Silver Seahorse | 4E | +| Vintage Pirate Hat | 7E | + +</td><td></td><td> + +| Location Name | Coordinates | Quadrant | +| ------------------------------------- | ----------- | --------- | +| Seaside Cottages | ("1", "C") | Blue | +| Aqua Lagoon (Island of Mystery) | ("1", "F") | Yellow | +| Deserted Docks | ("2", "A") | Blue | +| Spiky Rocks | ("3", "D") | Yellow | +| Abandoned Lighthouse | ("4", "B") | Blue | +| Hidden Spring (Island of Mystery) | ("4", "E") | Yellow | +| Stormy Breakwater | ("5", "B") | Purple | +| Old Schooner | ("6", "A") | Purple | +| Tangled Seaweed Patch | ("6", "D") | Orange | +| Quiet Inlet (Island of Mystery) | ("7", "E") | Orange | +| Windswept Hilltop (Island of Mystery) | ("7", "F") | Orange | +| Harbor Managers Office | ("8", "A") | Purple | +| Foggy Seacave | ("8", "C") | Purple | + +</td></tr> +</table> + +<br> + +But things are a bit disorganized: Azara's coordinates appear to be formatted and sorted differently from Rui's, and they have to keep looking from one list to the other to figure out which treasures go with which locations. +Being budding pythonistas, they have come to you for help in writing a small program (a set of functions, really) to better organize their hunt information. + + +## 1. Extract coordinates + +Implement the `get_coordinate()` function that takes a `(treasure, coordinate)` pair from Azara's list and returns only the extracted map coordinate. + + +```python +>>> get_coordinate(('Scrimshawed Whale Tooth', '2A')) +2A +``` + +## 2. Format coordinates + +Implement the `convert_coordinate()` function that takes a coordinate in the format "2A" and returns a tuple in the format `("2", "A")`. + + +```python +>>> convert_coordinate("2A") +("2", "A") +``` + +## 3. Match coordinates + +Implement the `compare_records()` function that takes a `(treasure, coordinate)` pair and a `(location, coordinate, quadrant)` record and compares coordinates from each. +Return **`True`** if the coordinates "match", and return **`False`** if they do not. +Re-format coordinates as needed for accurate comparison. + + +```python +>>> compare_records(('Brass Spyglass', '4B'), ('Seaside Cottages', ('1', 'C'), 'blue')) +False + +>>> compare_records(('Model Ship in Large Bottle', '8A'), ('Harbor Managers Office', ('8', 'A'), 'purple')) +True +``` + +## 4. Combine matched records + +Implement the `create_record()` function that takes a `(treasure, coordinate)` pair from Azara's list and a `(location, coordinate, quadrant)` record from Rui's list and returns `(treasure, coordinate, location, coordinate, quadrant)` **if the coordinates match**. +If the coordinates _do not_ match, return the string **"not a match"**. +Re-format the coordinate as needed for accurate comparison. + + +```python +>>> create_record(('Brass Spyglass', '4B'), ('Abandoned Lighthouse', ('4', 'B'), 'Blue')) +('Brass Spyglass', '4B', 'Abandoned Lighthouse', ('4', 'B'), 'Blue') + +>>> create_record(('Brass Spyglass', '4B'), ('Seaside Cottages', ('1', 'C'), 'blue')) +"not a match" +``` + +## 5. "Clean up" & make a report of all records + +Clean up the combined records from Azara and Rui so that there's only one set of coordinates per record. Make a report so they can see one list of everything they need to put on their maps. +Implement the `clean_up()` function that takes a tuple of tuples (_everything from both lists_), looping through the _outer_ tuple, dropping the unwanted coordinates from each _inner_ tuple and adding each to a 'report'. +Format and return the 'report' so that there is one cleaned record on each line. + + +```python +>>> clean_up((('Brass Spyglass', '4B', 'Abandoned Lighthouse', ('4', 'B'), 'Blue'), ('Vintage Pirate Hat', '7E', 'Quiet Inlet (Island of Mystery)', ('7', 'E'), 'Orange'), ('Crystal Crab', '6A', 'Old Schooner', ('6', 'A'), 'Purple'))) + +""" +('Brass Spyglass', 'Abandoned Lighthouse', ('4', 'B'), 'Blue')\n +('Vintage Pirate Hat', 'Quiet Inlet (Island of Mystery)', ('7', 'E'), 'Orange')\n +('Crystal Crab', 'Old Schooner', ('6', 'A'), 'Purple')\n +""" +``` + +## Source + +### Created by + +- @BethanyG \ No newline at end of file diff --git a/python/tisbury-treasure-hunt/__pycache__/tuples.cpython-313.pyc b/python/tisbury-treasure-hunt/__pycache__/tuples.cpython-313.pyc new file mode 100644 index 0000000..cd5990b Binary files /dev/null and b/python/tisbury-treasure-hunt/__pycache__/tuples.cpython-313.pyc differ diff --git a/python/tisbury-treasure-hunt/__pycache__/tuples.cpython-314.pyc b/python/tisbury-treasure-hunt/__pycache__/tuples.cpython-314.pyc new file mode 100644 index 0000000..8761ec7 Binary files /dev/null and b/python/tisbury-treasure-hunt/__pycache__/tuples.cpython-314.pyc differ diff --git a/python/tisbury-treasure-hunt/__pycache__/tuples_test.cpython-313-pytest-8.3.4.pyc b/python/tisbury-treasure-hunt/__pycache__/tuples_test.cpython-313-pytest-8.3.4.pyc new file mode 100644 index 0000000..7f3319d Binary files /dev/null and b/python/tisbury-treasure-hunt/__pycache__/tuples_test.cpython-313-pytest-8.3.4.pyc differ diff --git a/python/tisbury-treasure-hunt/__pycache__/tuples_test.cpython-314-pytest-9.1.0.pyc b/python/tisbury-treasure-hunt/__pycache__/tuples_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..e547a95 Binary files /dev/null and b/python/tisbury-treasure-hunt/__pycache__/tuples_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/tisbury-treasure-hunt/tuples.py b/python/tisbury-treasure-hunt/tuples.py new file mode 100644 index 0000000..386598d --- /dev/null +++ b/python/tisbury-treasure-hunt/tuples.py @@ -0,0 +1,60 @@ +"""Functions to help Azara and Rui locate pirate treasure.""" + + +def get_coordinate(record): + """Return coordinate value from a tuple containing the treasure name, and treasure coordinate. + + :param record: tuple - with a (treasure, coordinate) pair. + :return: str - the extracted map coordinate. + """ + return record[1] + + +def convert_coordinate(coordinate): + """Split the given coordinate into tuple containing its individual components. + + :param coordinate: str - a string map coordinate + :return: tuple - the string coordinate split into its individual components. + """ + return (coordinate[0], coordinate[1]) + + +def compare_records(azara_record, rui_record): + """Compare two record types and determine if their coordinates match. + + :param azara_record: tuple - a (treasure, coordinate) pair. + :param rui_record: tuple - a (location, tuple(coordinate_1, coordinate_2), quadrant) trio. + :return: bool - do the coordinates match? + """ + azara_converted_coordinate: tuple = convert_coordinate(azara_record[1]) + rui_coordinate: tuple = rui_record[1] + return azara_converted_coordinate == rui_coordinate + + +def create_record(azara_record, rui_record): + """Combine the two record types (if possible) and create a combined record group. + + :param azara_record: tuple - a (treasure, coordinate) pair. + :param rui_record: tuple - a (location, coordinate, quadrant) trio. + :return: tuple or str - the combined record (if compatible), or the string "not a match" (if incompatible). + """ + if compare_records(azara_record, rui_record): + return azara_record + rui_record + return "not a match" + + +def clean_up(combined_record_group): + """Clean up a combined record group into a multi-line string of single records. + + :param combined_record_group: tuple - everything from both participants. + :return: str - everything "cleaned", excess coordinates and information are removed. + + The return statement should be a multi-lined string with items separated by newlines. + + (see HINTS.md for an example). + """ + # azara_record[0] + rui_record[0] + rui_record[1] + rui_record[2] + cleaned_string: str = "" + for data in combined_record_group: + cleaned_string += f"('{data[0]}', '{data[2]}', {data[3]}, '{data[4]}')\n" + return cleaned_string diff --git a/python/tisbury-treasure-hunt/tuples_test.py b/python/tisbury-treasure-hunt/tuples_test.py new file mode 100644 index 0000000..6bd8a50 --- /dev/null +++ b/python/tisbury-treasure-hunt/tuples_test.py @@ -0,0 +1,160 @@ +import unittest +import pytest +from tuples import (get_coordinate, + convert_coordinate, + compare_records, + create_record, + clean_up) + + +class TisburyTreasureTest(unittest.TestCase): + + @pytest.mark.task(taskno=1) + def test_get_coordinate(self): + input_data = [('Scrimshawed Whale Tooth', '2A'), + ('Brass Spyglass', '4B'), + ('Robot Parrot', '1C'), + ('Glass Starfish', '6D'), + ('Vintage Pirate Hat', '7E'), + ('Pirate Flag', '7F'), + ('Crystal Crab', '6A'), + ('Model Ship in Large Bottle', '8A'), + ('Angry Monkey Figurine', '5B'), + ('Carved Wooden Elephant', '8C'), + ('Amethyst Octopus', '1F'), + ('Antique Glass Fishnet Float', '3D'), + ('Silver Seahorse', '4E')] + + result_data = ['2A', '4B', '1C', '6D', '7E', '7F', '6A', '8A', '5B', '8C', '1F', '3D', '4E'] + + for variant, (item, expected) in enumerate(zip(input_data, result_data), start=1): + with self.subTest(f'variation #{variant}', item=item, expected=expected): + actual_result = get_coordinate(item) + error_message = (f'Called get_coordinate({item}). ' + f'The function returned "{actual_result}", but ' + f'the tests expected "{expected}" as the coordinates.') + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=2) + def test_convert_coordinate(self): + input_data = ['2A', '4B', '1C', '6D', '7E', '7F', + '6A', '8A', '5B', '8C', '1F', '3D', '4E'] + result_data = [('2', 'A'), + ('4', 'B'), + ('1', 'C'), + ('6', 'D'), + ('7', 'E'), + ('7', 'F'), + ('6', 'A'), + ('8', 'A'), + ('5', 'B'), + ('8', 'C'), + ('1', 'F'), + ('3', 'D'), + ('4', 'E')] + + for variant, (item, expected) in enumerate(zip(input_data, result_data), start=1): + with self.subTest(f'variation #{variant}', item=item, expected=expected): + actual_result = convert_coordinate(item) + error_message = (f'Called convert_coordinate({item}). ' + f'The function returned {actual_result}, but the ' + f'tests expected {expected} as the converted coordinate.') + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=3) + def test_compare_records(self): + input_data = [ + (('Scrimshawed Whale Tooth', '2A'), ('Deserted Docks', ('2', 'A'), 'Blue')), + (('Brass Spyglass', '4B'), ('Abandoned Lighthouse', ('4', 'B'), 'Blue')), + (('Robot Parrot', '1C'), ('Seaside Cottages', ('1', 'C'), 'Blue')), + (('Glass Starfish', '6D'), ('Tangled Seaweed Patch', ('6', 'D'), 'Orange')), + (('Vintage Pirate Hat', '7E'), ('Quiet Inlet (Island of Mystery)', ('7', 'E'), 'Orange')), + (('Amethyst Octopus', '1F'), ('Seaside Cottages', ('1', 'C'), 'Blue')), + (('Angry Monkey Figurine', '5B'), ('Aqua Lagoon (Island of Mystery)', ('1', 'F'), 'Yellow')), + (('Antique Glass Fishnet Float', '3D'), ('Deserted Docks', ('2', 'A'), 'Blue')), + (('Brass Spyglass', '4B'), ('Spiky Rocks', ('3', 'D'), 'Yellow')), + (('Carved Wooden Elephant', '8C'), ('Abandoned Lighthouse', ('4', 'B'), 'Blue')) + ] + result_data = [True, True, True, True, True, False, False, False, False, False] + + for variant, (item, expected) in enumerate(zip(input_data, result_data), start=1): + with self.subTest(f'variation #{variant}', item=item, expected=expected): + actual_result = compare_records(item[0], item[1]) + error_message = (f'Called compare_records({item[0]}, {item[1]}). ' + f'The function returned {actual_result}, but the ' + f'tests expected {expected}.') + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=4) + def test_create_record(self): + input_data = [ + (('Angry Monkey Figurine', '5B'), ('Stormy Breakwater', ('5', 'B'), 'Purple')), + (('Carved Wooden Elephant', '8C'), ('Foggy Seacave', ('8', 'C'), 'Purple')), + (('Amethyst Octopus', '1F'), ('Aqua Lagoon (Island of Mystery)', ('1', 'F'), 'Yellow')), + (('Antique Glass Fishnet Float', '3D'), ('Spiky Rocks', ('3', 'D'), 'Yellow')), + (('Silver Seahorse', '4E'), ('Hidden Spring (Island of Mystery)', ('4', 'E'), 'Yellow')), + (('Amethyst Octopus', '1F'), ('Seaside Cottages', ('1', 'C'), 'Blue')), + (('Angry Monkey Figurine', '5B'), ('Aqua Lagoon (Island of Mystery)', ('1', 'F'), 'Yellow')), + (('Antique Glass Fishnet Float', '3D'), ('Deserted Docks', ('2', 'A'), 'Blue')), + (('Brass Spyglass', '4B'), ('Spiky Rocks', ('3', 'D'), 'Yellow')), + (('Carved Wooden Elephant', '8C'), ('Abandoned Lighthouse', ('4', 'B'), 'Blue')) + ] + result_data = [ + ('Angry Monkey Figurine', '5B', 'Stormy Breakwater', ('5', 'B'), 'Purple'), + ('Carved Wooden Elephant', '8C', 'Foggy Seacave', ('8', 'C'), 'Purple'), + ('Amethyst Octopus', '1F', 'Aqua Lagoon (Island of Mystery)', ('1', 'F'), 'Yellow'), + ('Antique Glass Fishnet Float', '3D', 'Spiky Rocks', ('3', 'D'), 'Yellow'), + ('Silver Seahorse', '4E', 'Hidden Spring (Island of Mystery)', ('4', 'E'), 'Yellow'), + 'not a match', + 'not a match', + 'not a match', + 'not a match', + 'not a match' + ] + + for variant, (item, expected) in enumerate(zip(input_data, result_data), start=1): + with self.subTest(f'variation #{variant}', item=item, expected=expected): + actual_result = create_record(item[0], item[1]) + error_message = (f'Called create_record({item[0]},{item[1]}). ' + f'The function returned ' + f'{actual_result}, but the tests expected ' + f'{expected} for the record.') + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=5) + def test_clean_up(self): + input_data = ( + ('Scrimshawed Whale Tooth', '2A', 'Deserted Docks', ('2', 'A'), 'Blue'), + ('Brass Spyglass', '4B', 'Abandoned Lighthouse', ('4', 'B'), 'Blue'), + ('Robot Parrot', '1C', 'Seaside Cottages', ('1', 'C'), 'Blue'), + ('Glass Starfish', '6D', 'Tangled Seaweed Patch', ('6', 'D'), 'Orange'), + ('Vintage Pirate Hat', '7E', 'Quiet Inlet (Island of Mystery)', ('7', 'E'), 'Orange'), + ('Pirate Flag', '7F', 'Windswept Hilltop (Island of Mystery)', ('7', 'F'), 'Orange'), + ('Crystal Crab', '6A', 'Old Schooner', ('6', 'A'), 'Purple'), + ('Model Ship in Large Bottle', '8A', 'Harbor Managers Office', ('8', 'A'), 'Purple'), + ('Angry Monkey Figurine', '5B', 'Stormy Breakwater', ('5', 'B'), 'Purple'), + ('Carved Wooden Elephant', '8C', 'Foggy Seacave', ('8', 'C'), 'Purple'), + ('Amethyst Octopus', '1F', 'Aqua Lagoon (Island of Mystery)', ('1', 'F'), 'Yellow'), + ('Antique Glass Fishnet Float', '3D', 'Spiky Rocks', ('3', 'D'), 'Yellow'), + ('Silver Seahorse', '4E', 'Hidden Spring (Island of Mystery)', ('4', 'E'), 'Yellow') + ) + + result_data = """('Scrimshawed Whale Tooth', 'Deserted Docks', ('2', 'A'), 'Blue')\n\ +('Brass Spyglass', 'Abandoned Lighthouse', ('4', 'B'), 'Blue')\n\ +('Robot Parrot', 'Seaside Cottages', ('1', 'C'), 'Blue')\n\ +('Glass Starfish', 'Tangled Seaweed Patch', ('6', 'D'), 'Orange')\n\ +('Vintage Pirate Hat', 'Quiet Inlet (Island of Mystery)', ('7', 'E'), 'Orange')\n\ +('Pirate Flag', 'Windswept Hilltop (Island of Mystery)', ('7', 'F'), 'Orange')\n\ +('Crystal Crab', 'Old Schooner', ('6', 'A'), 'Purple')\n\ +('Model Ship in Large Bottle', 'Harbor Managers Office', ('8', 'A'), 'Purple')\n\ +('Angry Monkey Figurine', 'Stormy Breakwater', ('5', 'B'), 'Purple')\n\ +('Carved Wooden Elephant', 'Foggy Seacave', ('8', 'C'), 'Purple')\n\ +('Amethyst Octopus', 'Aqua Lagoon (Island of Mystery)', ('1', 'F'), 'Yellow')\n\ +('Antique Glass Fishnet Float', 'Spiky Rocks', ('3', 'D'), 'Yellow')\n\ +('Silver Seahorse', 'Hidden Spring (Island of Mystery)', ('4', 'E'), 'Yellow')\n""" + + self.assertEqual(clean_up(input_data), result_data) diff --git a/python/triangle/.exercism/config.json b/python/triangle/.exercism/config.json new file mode 100644 index 0000000..041bf28 --- /dev/null +++ b/python/triangle/.exercism/config.json @@ -0,0 +1,36 @@ +{ + "authors": [], + "contributors": [ + "behrtam", + "BethanyG", + "cmccandless", + "Dog", + "ikhadykin", + "kytrinyx", + "lowks", + "mpatibandla", + "N-Parsons", + "Nishant23", + "pheanex", + "rozuur", + "sjakobi", + "Stigjb", + "tqa236", + "xitanggg", + "YuriyCherniy" + ], + "files": { + "solution": [ + "triangle.py" + ], + "test": [ + "triangle_test.py" + ], + "example": [ + ".meta/example.py" + ] + }, + "blurb": "Determine if a triangle is equilateral, isosceles, or scalene.", + "source": "The Ruby Koans triangle project, parts 1 & 2", + "source_url": "https://web.archive.org/web/20220831105330/http://rubykoans.com" +} diff --git a/python/triangle/.exercism/metadata.json b/python/triangle/.exercism/metadata.json new file mode 100644 index 0000000..095a1ac --- /dev/null +++ b/python/triangle/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"triangle","id":"fe581408dd64463f956ee1f7a6d7cc57","url":"https://exercism.org/tracks/python/exercises/triangle","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/triangle/HELP.md b/python/triangle/HELP.md new file mode 100644 index 0000000..2d9233f --- /dev/null +++ b/python/triangle/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +<br> + +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit triangle.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/triangle/README.md b/python/triangle/README.md new file mode 100644 index 0000000..961c673 --- /dev/null +++ b/python/triangle/README.md @@ -0,0 +1,60 @@ +# Triangle + +Welcome to Triangle on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Instructions + +Determine if a triangle is equilateral, isosceles, or scalene. + +An _equilateral_ triangle has all three sides the same length. + +An _isosceles_ triangle has at least two sides the same length. +(It is sometimes specified as having exactly two sides the same length, but for the purposes of this exercise we'll say at least two.) + +A _scalene_ triangle has all sides of different lengths. + +## Note + +For a shape to be a triangle at all, all sides have to be of length > 0, and the sum of the lengths of any two sides must be greater than or equal to the length of the third side. + +In equations: + +Let `a`, `b`, and `c` be sides of the triangle. +Then all three of the following expressions must be true: + +```text +a + b ≥ c +b + c ≥ a +a + c ≥ b +``` + +See [Triangle Inequality][triangle-inequality] + +[triangle-inequality]: https://en.wikipedia.org/wiki/Triangle_inequality + +## Source + +### Contributed to by + +- @behrtam +- @BethanyG +- @cmccandless +- @Dog +- @ikhadykin +- @kytrinyx +- @lowks +- @mpatibandla +- @N-Parsons +- @Nishant23 +- @pheanex +- @rozuur +- @sjakobi +- @Stigjb +- @tqa236 +- @xitanggg +- @YuriyCherniy + +### Based on + +The Ruby Koans triangle project, parts 1 & 2 - https://web.archive.org/web/20220831105330/http://rubykoans.com \ No newline at end of file diff --git a/python/triangle/__pycache__/triangle.cpython-313.pyc b/python/triangle/__pycache__/triangle.cpython-313.pyc new file mode 100644 index 0000000..70fa181 Binary files /dev/null and b/python/triangle/__pycache__/triangle.cpython-313.pyc differ diff --git a/python/triangle/__pycache__/triangle.cpython-314.pyc b/python/triangle/__pycache__/triangle.cpython-314.pyc new file mode 100644 index 0000000..8a6c44a Binary files /dev/null and b/python/triangle/__pycache__/triangle.cpython-314.pyc differ diff --git a/python/triangle/__pycache__/triangle_test.cpython-313-pytest-8.3.4.pyc b/python/triangle/__pycache__/triangle_test.cpython-313-pytest-8.3.4.pyc new file mode 100644 index 0000000..2c78d46 Binary files /dev/null and b/python/triangle/__pycache__/triangle_test.cpython-313-pytest-8.3.4.pyc differ diff --git a/python/triangle/__pycache__/triangle_test.cpython-314-pytest-9.1.0.pyc b/python/triangle/__pycache__/triangle_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..c1f9f78 Binary files /dev/null and b/python/triangle/__pycache__/triangle_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/triangle/triangle.py b/python/triangle/triangle.py new file mode 100644 index 0000000..c86c7e5 --- /dev/null +++ b/python/triangle/triangle.py @@ -0,0 +1,31 @@ +def equilateral(sides): + for side in sides: + if side == 0: + return False + return (sides[0] == sides[1]) and (sides[0] == sides[2]) and (sides[1] == sides[2]) + + +def isosceles(sides): + for side in sides: + if side == 0: + return False + if ( + (sides[0] + sides[1] < sides[2]) + or (sides[1] + sides[2] < sides[0]) + or (sides[2] + sides[0] < sides[1]) + ): + return False + return (sides[0] == sides[1]) or (sides[0] == sides[2]) or (sides[1] == sides[2]) + + +def scalene(sides): + for side in sides: + if side == 0: + return False + if ( + (sides[0] + sides[1] < sides[2]) + or (sides[1] + sides[2] < sides[0]) + or (sides[2] + sides[0] < sides[1]) + ): + return False + return (sides[0] != sides[1]) and (sides[0] != sides[2]) and (sides[1] != sides[2]) diff --git a/python/triangle/triangle_test.py b/python/triangle/triangle_test.py new file mode 100644 index 0000000..b279c83 --- /dev/null +++ b/python/triangle/triangle_test.py @@ -0,0 +1,80 @@ +# These tests are auto-generated with test data from: +# https://github.com/exercism/problem-specifications/tree/main/exercises/triangle/canonical-data.json +# File last updated on 2023-07-19 + +import unittest + +from triangle import ( + equilateral, + isosceles, + scalene, +) + + +class EquilateralTriangleTest(unittest.TestCase): + def test_all_sides_are_equal(self): + self.assertIs(equilateral([2, 2, 2]), True) + + def test_any_side_is_unequal(self): + self.assertIs(equilateral([2, 3, 2]), False) + + def test_no_sides_are_equal(self): + self.assertIs(equilateral([5, 4, 6]), False) + + def test_all_zero_sides_is_not_a_triangle(self): + self.assertIs(equilateral([0, 0, 0]), False) + + def test_sides_may_be_floats(self): + self.assertIs(equilateral([0.5, 0.5, 0.5]), True) + + +class IsoscelesTriangleTest(unittest.TestCase): + def test_last_two_sides_are_equal(self): + self.assertIs(isosceles([3, 4, 4]), True) + + def test_first_two_sides_are_equal(self): + self.assertIs(isosceles([4, 4, 3]), True) + + def test_first_and_last_sides_are_equal(self): + self.assertIs(isosceles([4, 3, 4]), True) + + def test_equilateral_triangles_are_also_isosceles(self): + self.assertIs(isosceles([4, 4, 4]), True) + + def test_no_sides_are_equal(self): + self.assertIs(isosceles([2, 3, 4]), False) + + def test_first_triangle_inequality_violation(self): + self.assertIs(isosceles([1, 1, 3]), False) + + def test_second_triangle_inequality_violation(self): + self.assertIs(isosceles([1, 3, 1]), False) + + def test_third_triangle_inequality_violation(self): + self.assertIs(isosceles([3, 1, 1]), False) + + def test_sides_may_be_floats(self): + self.assertIs(isosceles([0.5, 0.4, 0.5]), True) + + +class ScaleneTriangleTest(unittest.TestCase): + def test_no_sides_are_equal(self): + self.assertIs(scalene([5, 4, 6]), True) + + def test_all_sides_are_equal(self): + self.assertIs(scalene([4, 4, 4]), False) + + def test_first_and_second_sides_are_equal(self): + self.assertIs(scalene([4, 4, 3]), False) + + def test_first_and_third_sides_are_equal(self): + self.assertIs(scalene([3, 4, 3]), False) + + def test_second_and_third_sides_are_equal(self): + self.assertIs(scalene([4, 3, 3]), False) + + def test_may_not_violate_triangle_inequality(self): + self.assertIs(scalene([7, 3, 2]), False) + + def test_sides_may_be_floats(self): + self.assertIs(scalene([0.5, 0.4, 0.6]), True) diff --git a/python/two-fer/.exercism/config.json b/python/two-fer/.exercism/config.json new file mode 100644 index 0000000..24e71e7 --- /dev/null +++ b/python/two-fer/.exercism/config.json @@ -0,0 +1,30 @@ +{ + "authors": [ + "samwincott" + ], + "contributors": [ + "cmccandless", + "denislooby", + "Dog", + "Grociu", + "ikhadykin", + "mikeyny", + "N-Parsons", + "tqa236", + "xarxziux", + "yawpitch" + ], + "files": { + "solution": [ + "two_fer.py" + ], + "test": [ + "two_fer_test.py" + ], + "example": [ + ".meta/example.py" + ] + }, + "blurb": "Create a sentence of the form \"One for X, one for me.\".", + "source_url": "https://github.com/exercism/problem-specifications/issues/757" +} diff --git a/python/two-fer/.exercism/metadata.json b/python/two-fer/.exercism/metadata.json new file mode 100644 index 0000000..5950287 --- /dev/null +++ b/python/two-fer/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"two-fer","id":"653da66296304fefa147345a40ba08ce","url":"https://exercism.org/tracks/python/exercises/two-fer","handle":"sanctushck","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/two-fer/HELP.md b/python/two-fer/HELP.md new file mode 100644 index 0000000..dd35854 --- /dev/null +++ b/python/two-fer/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +<br> + +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit two_fer.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/two-fer/README.md b/python/two-fer/README.md new file mode 100644 index 0000000..2954d61 --- /dev/null +++ b/python/two-fer/README.md @@ -0,0 +1,61 @@ +# Two Fer + +Welcome to Two Fer on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Introduction + +In some English accents, when you say "two for" quickly, it sounds like "two fer". +Two-for-one is a way of saying that if you buy one, you also get one for free. +So the phrase "two-fer" often implies a two-for-one offer. + +Imagine a bakery that has a holiday offer where you can buy two cookies for the price of one ("two-fer one!"). +You take the offer and (very generously) decide to give the extra cookie to someone else in the queue. + +## Instructions + +Your task is to determine what you will say as you give away the extra cookie. + +If you know the person's name (e.g. if they're named Do-yun), then you will say: + +```text +One for Do-yun, one for me. +``` + +If you don't know the person's name, you will say _you_ instead. + +```text +One for you, one for me. +``` + +Here are some examples: + +| Name | Dialogue | +| :----- | :-------------------------- | +| Alice | One for Alice, one for me. | +| Bohdan | One for Bohdan, one for me. | +| | One for you, one for me. | +| Zaphod | One for Zaphod, one for me. | + +## Source + +### Created by + +- @samwincott + +### Contributed to by + +- @cmccandless +- @denislooby +- @Dog +- @Grociu +- @ikhadykin +- @mikeyny +- @N-Parsons +- @tqa236 +- @xarxziux +- @yawpitch + +### Based on + +https://github.com/exercism/problem-specifications/issues/757 \ No newline at end of file diff --git a/python/two-fer/__pycache__/two_fer.cpython-313.pyc b/python/two-fer/__pycache__/two_fer.cpython-313.pyc new file mode 100644 index 0000000..d419f60 Binary files /dev/null and b/python/two-fer/__pycache__/two_fer.cpython-313.pyc differ diff --git a/python/two-fer/__pycache__/two_fer.cpython-314.pyc b/python/two-fer/__pycache__/two_fer.cpython-314.pyc new file mode 100644 index 0000000..9879199 Binary files /dev/null and b/python/two-fer/__pycache__/two_fer.cpython-314.pyc differ diff --git a/python/two-fer/__pycache__/two_fer_test.cpython-313-pytest-8.3.5.pyc b/python/two-fer/__pycache__/two_fer_test.cpython-313-pytest-8.3.5.pyc new file mode 100644 index 0000000..2d5d41d Binary files /dev/null and b/python/two-fer/__pycache__/two_fer_test.cpython-313-pytest-8.3.5.pyc differ diff --git a/python/two-fer/__pycache__/two_fer_test.cpython-314-pytest-9.1.0.pyc b/python/two-fer/__pycache__/two_fer_test.cpython-314-pytest-9.1.0.pyc new file mode 100644 index 0000000..d265f20 Binary files /dev/null and b/python/two-fer/__pycache__/two_fer_test.cpython-314-pytest-9.1.0.pyc differ diff --git a/python/two-fer/two_fer.py b/python/two-fer/two_fer.py new file mode 100644 index 0000000..7bafac4 --- /dev/null +++ b/python/two-fer/two_fer.py @@ -0,0 +1,2 @@ +def two_fer(name: str = "you") -> str: + return f"One for {name}, one for me." diff --git a/python/two-fer/two_fer_test.py b/python/two-fer/two_fer_test.py new file mode 100644 index 0000000..fa032f0 --- /dev/null +++ b/python/two-fer/two_fer_test.py @@ -0,0 +1,20 @@ +# These tests are auto-generated with test data from: +# https://github.com/exercism/problem-specifications/tree/main/exercises/two-fer/canonical-data.json +# File last updated on 2023-07-19 + +import unittest + +from two_fer import ( + two_fer, +) + + +class TwoFerTest(unittest.TestCase): + def test_no_name_given(self): + self.assertEqual(two_fer(), "One for you, one for me.") + + def test_a_name_given(self): + self.assertEqual(two_fer("Alice"), "One for Alice, one for me.") + + def test_another_name_given(self): + self.assertEqual(two_fer("Bob"), "One for Bob, one for me.")