implement fudge dices, complete with unit tests
This commit is contained in:
		
							parent
							
								
									a289e8453a
								
							
						
					
					
						commit
						e3fd8815b0
					
				
							
								
								
									
										28
									
								
								lib/dice.c
									
									
									
									
									
								
							
							
						
						
									
										28
									
								
								lib/dice.c
									
									
									
									
									
								
							| @ -22,6 +22,7 @@ | |||||||
| 
 | 
 | ||||||
| #include <stdlib.h> | #include <stdlib.h> | ||||||
| #include <string.h> | #include <string.h> | ||||||
|  | #include <stdio.h> | ||||||
| 
 | 
 | ||||||
| #include "config.h" | #include "config.h" | ||||||
| 
 | 
 | ||||||
| @ -39,6 +40,7 @@ extern void yy_delete_buffer(void *b, void *scanner); | |||||||
| struct dice_ | struct dice_ | ||||||
| { | { | ||||||
|     int consumed; |     int consumed; | ||||||
|  |     bool fudge; | ||||||
| 
 | 
 | ||||||
|     uint32_t amount; |     uint32_t amount; | ||||||
|     uint32_t sides; |     uint32_t sides; | ||||||
| @ -137,6 +139,7 @@ bool dice_set(dice_t d, dice_option_t opt, ...) | |||||||
|     switch (opt) { |     switch (opt) { | ||||||
|     case DICEOPTION_AMOUNT: d->amount = va_arg(lst, uint32_t); break; |     case DICEOPTION_AMOUNT: d->amount = va_arg(lst, uint32_t); break; | ||||||
|     case DICEOPTION_SIDES: d->sides = va_arg(lst, uint32_t); break; |     case DICEOPTION_SIDES: d->sides = va_arg(lst, uint32_t); break; | ||||||
|  |     case DICEOPTION_FUDGE: d->fudge = va_arg(lst, uint32_t); break; | ||||||
|     case DICEOPTION_ERROR: |     case DICEOPTION_ERROR: | ||||||
|     { |     { | ||||||
|         char const *err = va_arg(lst, char const *); |         char const *err = va_arg(lst, char const *); | ||||||
| @ -175,6 +178,12 @@ bool dice_get(dice_t d, dice_option_t opt, ...) | |||||||
|         *ptr = d->error; |         *ptr = d->error; | ||||||
|     } break; |     } break; | ||||||
| 
 | 
 | ||||||
|  |     case DICEOPTION_FUDGE: | ||||||
|  |     { | ||||||
|  |         bool *ptr = va_arg(lst, uint32_t*); | ||||||
|  |         *ptr = d->fudge; | ||||||
|  |     } break; | ||||||
|  | 
 | ||||||
|     default: return false; |     default: return false; | ||||||
|     } |     } | ||||||
|     va_end(lst); |     va_end(lst); | ||||||
| @ -182,13 +191,24 @@ bool dice_get(dice_t d, dice_option_t opt, ...) | |||||||
|     return true; |     return true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static int dice_roll_fudge(void) | ||||||
|  | { | ||||||
|  |     static int results[6] = {-1, -1, 0, 0, +1, +1}; | ||||||
|  |     int idx = arc4random_uniform(sizeof(results)/sizeof(int)) + 1; | ||||||
|  |     return results[idx]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| int64_t dice_roll(dice_t d) | int64_t dice_roll(dice_t d) | ||||||
| { | { | ||||||
|     int64_t result = 0; |     int64_t result = 0; | ||||||
|     uint32_t i = 0; |     uint32_t i = 0; | ||||||
| 
 | 
 | ||||||
|     for (i = 0; i < d->amount; i++) { |     for (i = 0; i < d->amount; i++) { | ||||||
|         result += arc4random_uniform(d->sides) + 1; |         if (!d->fudge) { | ||||||
|  |             result += arc4random_uniform(d->sides) + 1; | ||||||
|  |         } else { | ||||||
|  |             result += dice_roll_fudge(); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return result; |     return result; | ||||||
| @ -211,7 +231,11 @@ bool dice_evaluate(dice_t d, dice_result_t **res, size_t *reslen) | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     for (i = 0; i < d->amount; i++) { |     for (i = 0; i < d->amount; i++) { | ||||||
|         r[i].result = arc4random_uniform(d->sides) + 1; |         if (!d->fudge) { | ||||||
|  |             r[i].result = arc4random_uniform(d->sides) + 1; | ||||||
|  |         } else { | ||||||
|  |             r[i].result = dice_roll_fudge(); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     *reslen = len; |     *reslen = len; | ||||||
|  | |||||||
| @ -53,6 +53,12 @@ typedef enum { | |||||||
|      * set: char const * |      * set: char const * | ||||||
|      */ |      */ | ||||||
|     DICEOPTION_ERROR, |     DICEOPTION_ERROR, | ||||||
|  | 
 | ||||||
|  |     /* Whether the dice has no amount but is a fudge dice instead.
 | ||||||
|  |      * get: uint32_t * | ||||||
|  |      * set: uint32_t | ||||||
|  |      */ | ||||||
|  |     DICEOPTION_FUDGE, | ||||||
| } dice_option_t; | } dice_option_t; | ||||||
| 
 | 
 | ||||||
| /* Creates a new dice object that is not initialised yet.
 | /* Creates a new dice object that is not initialised yet.
 | ||||||
|  | |||||||
| @ -22,4 +22,11 @@ extern void dice_update_consumed(dice_t d, int off); | |||||||
|     dice_update_consumed(d, yyleng); |     dice_update_consumed(d, yyleng); | ||||||
|     return TOK_DICESEP; |     return TOK_DICESEP; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | [fF] { | ||||||
|  |     dice_t d = yyget_extra(yyscanner); | ||||||
|  |     dice_update_consumed(d, yyleng); | ||||||
|  |     return TOK_FUDGE; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| %% | %% | ||||||
|  | |||||||
| @ -25,7 +25,7 @@ int yywrap(void) | |||||||
|     double number; |     double number; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| %token TOK_DICESEP | %token TOK_DICESEP TOK_FUDGE | ||||||
| %token  <integer>           TOK_INTEGER | %token  <integer>           TOK_INTEGER | ||||||
| 
 | 
 | ||||||
| %% | %% | ||||||
| @ -42,6 +42,20 @@ dice:           TOK_INTEGER TOK_DICESEP TOK_INTEGER | |||||||
|                     dice_set(dice, DICEOPTION_AMOUNT, 1); |                     dice_set(dice, DICEOPTION_AMOUNT, 1); | ||||||
|                     dice_set(dice, DICEOPTION_SIDES, $2); |                     dice_set(dice, DICEOPTION_SIDES, $2); | ||||||
| 
 | 
 | ||||||
|  |                     YYACCEPT; | ||||||
|  |                 } | ||||||
|  |         |       TOK_DICESEP TOK_FUDGE | ||||||
|  |                 { | ||||||
|  |                     dice_set(dice, DICEOPTION_AMOUNT, 1L); | ||||||
|  |                     dice_set(dice, DICEOPTION_FUDGE, 1L); | ||||||
|  | 
 | ||||||
|  |                     YYACCEPT; | ||||||
|  |                 } | ||||||
|  |         |       TOK_INTEGER TOK_DICESEP TOK_FUDGE | ||||||
|  |                 { | ||||||
|  |                     dice_set(dice, DICEOPTION_AMOUNT, $1); | ||||||
|  |                     dice_set(dice, DICEOPTION_FUDGE, 1L); | ||||||
|  | 
 | ||||||
|                     YYACCEPT; |                     YYACCEPT; | ||||||
|                 } |                 } | ||||||
|         ; |         ; | ||||||
|  | |||||||
| @ -1,6 +1,7 @@ | |||||||
| check_PROGRAMS =	test_dice_simple_roll \
 | check_PROGRAMS =	test_dice_simple_roll \
 | ||||||
| 			test_dice_parse \
 | 			test_dice_parse \
 | ||||||
| 			test_dice_evaluate \
 | 			test_dice_evaluate \
 | ||||||
|  | 			test_dice_fudge \
 | ||||||
| 			test_expr_parse | 			test_expr_parse | ||||||
| 
 | 
 | ||||||
| AM_CFLAGS =	-I../lib ${CMOCKA_CFLAGS} | AM_CFLAGS =	-I../lib ${CMOCKA_CFLAGS} | ||||||
|  | |||||||
							
								
								
									
										127
									
								
								tests/test_dice_fudge.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										127
									
								
								tests/test_dice_fudge.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,127 @@ | |||||||
|  | /*
 | ||||||
|  |  * This file is part of libdice. | ||||||
|  |  * | ||||||
|  |  * Copyright (C) 2018 Florian Stinglmayr <florian@n0la.org> | ||||||
|  |  * | ||||||
|  |  * libdice is free software: you can redistribute it and/or modify it | ||||||
|  |  * under the terms of the GNU Lesser General Public License as | ||||||
|  |  * published by the Free Software Foundation, either version 3 of the | ||||||
|  |  * License, or (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * libdice is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||||
|  |  * GNU Lesser General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU Lesser General Public License | ||||||
|  |  * along with libdice.  If not, see <http://www.gnu.org/licenses/>.
 | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #include <dice.h> | ||||||
|  | 
 | ||||||
|  | #include <setjmp.h> | ||||||
|  | #include <cmocka.h> | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <string.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  | 
 | ||||||
|  | static void test_dice_fudge_construct(void **data) | ||||||
|  | { | ||||||
|  |     dice_t d = dice_new(); | ||||||
|  |     bool fudge = true; | ||||||
|  | 
 | ||||||
|  |     dice_get(d, DICEOPTION_FUDGE, &fudge); | ||||||
|  |     assert_false(fudge); | ||||||
|  | 
 | ||||||
|  |     dice_free(d); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void test_dice_fudge_set(void **data) | ||||||
|  | { | ||||||
|  |     dice_t d = dice_new(); | ||||||
|  |     bool fudge = false; | ||||||
|  | 
 | ||||||
|  |     dice_set(d, DICEOPTION_FUDGE, true); | ||||||
|  |     dice_get(d, DICEOPTION_FUDGE, &fudge); | ||||||
|  | 
 | ||||||
|  |     assert_true(fudge); | ||||||
|  |     dice_free(d); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void test_dice_fudge_roll_one(void **data) | ||||||
|  | { | ||||||
|  |     dice_t d = dice_new(); | ||||||
|  |     int result = 0, i = 0; | ||||||
|  | 
 | ||||||
|  |     dice_set(d, DICEOPTION_FUDGE, true); | ||||||
|  |     dice_set(d, DICEOPTION_AMOUNT, 1L); | ||||||
|  | 
 | ||||||
|  |     for (i = 0; i < 100000; i++) { | ||||||
|  |         result = dice_roll(d); | ||||||
|  |         assert_true(result >= -1 && result <= 1); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     dice_free(d); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void test_dice_fudge_roll_more(void **data) | ||||||
|  | { | ||||||
|  |     dice_t d = dice_new(); | ||||||
|  |     int result = 0, i = 0; | ||||||
|  | 
 | ||||||
|  |     dice_set(d, DICEOPTION_FUDGE, true); | ||||||
|  |     dice_set(d, DICEOPTION_AMOUNT, 6L); | ||||||
|  | 
 | ||||||
|  |     for (i = 0; i < 100000; i++) { | ||||||
|  |         result = dice_roll(d); | ||||||
|  |         assert_true(result >= -6 && result <= 6); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     dice_free(d); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void test_dice_fudge_parse1(void **data) | ||||||
|  | { | ||||||
|  |     dice_t d = dice_new(); | ||||||
|  |     int amount = 0, fudge = false; | ||||||
|  | 
 | ||||||
|  |     assert_true(dice_parse(d, "4dF")); | ||||||
|  | 
 | ||||||
|  |     dice_get(d, DICEOPTION_AMOUNT, &amount); | ||||||
|  |     dice_get(d, DICEOPTION_FUDGE, &fudge); | ||||||
|  | 
 | ||||||
|  |     assert_int_equal(amount, 4); | ||||||
|  |     assert_true(fudge); | ||||||
|  | 
 | ||||||
|  |     dice_free(d); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void test_dice_fudge_parse2(void **data) | ||||||
|  | { | ||||||
|  |     dice_t d = dice_new(); | ||||||
|  |     int amount = 0, fudge = false; | ||||||
|  | 
 | ||||||
|  |     assert_true(dice_parse(d, "df")); | ||||||
|  | 
 | ||||||
|  |     dice_get(d, DICEOPTION_AMOUNT, &amount); | ||||||
|  |     dice_get(d, DICEOPTION_FUDGE, &fudge); | ||||||
|  | 
 | ||||||
|  |     assert_int_equal(amount, 1); | ||||||
|  |     assert_true(fudge); | ||||||
|  | 
 | ||||||
|  |     dice_free(d); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int main(int ac, char **av) | ||||||
|  | { | ||||||
|  |     const struct CMUnitTest tests[] = { | ||||||
|  |         cmocka_unit_test(test_dice_fudge_construct), | ||||||
|  |         cmocka_unit_test(test_dice_fudge_set), | ||||||
|  |         cmocka_unit_test(test_dice_fudge_roll_one), | ||||||
|  |         cmocka_unit_test(test_dice_fudge_roll_more), | ||||||
|  |         cmocka_unit_test(test_dice_fudge_parse1), | ||||||
|  |         cmocka_unit_test(test_dice_fudge_parse2), | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     return cmocka_run_group_tests(tests, NULL, NULL); | ||||||
|  | } | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user