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 <string.h> | ||||
| #include <stdio.h> | ||||
| 
 | ||||
| #include "config.h" | ||||
| 
 | ||||
| @ -39,6 +40,7 @@ extern void yy_delete_buffer(void *b, void *scanner); | ||||
| struct dice_ | ||||
| { | ||||
|     int consumed; | ||||
|     bool fudge; | ||||
| 
 | ||||
|     uint32_t amount; | ||||
|     uint32_t sides; | ||||
| @ -137,6 +139,7 @@ bool dice_set(dice_t d, dice_option_t opt, ...) | ||||
|     switch (opt) { | ||||
|     case DICEOPTION_AMOUNT: d->amount = 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: | ||||
|     { | ||||
|         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; | ||||
|     } break; | ||||
| 
 | ||||
|     case DICEOPTION_FUDGE: | ||||
|     { | ||||
|         bool *ptr = va_arg(lst, uint32_t*); | ||||
|         *ptr = d->fudge; | ||||
|     } break; | ||||
| 
 | ||||
|     default: return false; | ||||
|     } | ||||
|     va_end(lst); | ||||
| @ -182,13 +191,24 @@ bool dice_get(dice_t d, dice_option_t opt, ...) | ||||
|     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 result = 0; | ||||
|     uint32_t i = 0; | ||||
| 
 | ||||
|     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; | ||||
| @ -211,7 +231,11 @@ bool dice_evaluate(dice_t d, dice_result_t **res, size_t *reslen) | ||||
|     } | ||||
| 
 | ||||
|     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; | ||||
|  | ||||
| @ -53,6 +53,12 @@ typedef enum { | ||||
|      * set: char const * | ||||
|      */ | ||||
|     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; | ||||
| 
 | ||||
| /* 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); | ||||
|     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; | ||||
| } | ||||
| 
 | ||||
| %token TOK_DICESEP | ||||
| %token TOK_DICESEP TOK_FUDGE | ||||
| %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_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; | ||||
|                 } | ||||
|         ; | ||||
|  | ||||
| @ -1,6 +1,7 @@ | ||||
| check_PROGRAMS =	test_dice_simple_roll \
 | ||||
| 			test_dice_parse \
 | ||||
| 			test_dice_evaluate \
 | ||||
| 			test_dice_fudge \
 | ||||
| 			test_expr_parse | ||||
| 
 | ||||
| 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