mirror of
https://github.com/caperren/school_archives.git
synced 2025-11-09 13:41:13 +00:00
Added Software Engineering II code
This commit is contained in:
@@ -0,0 +1,139 @@
|
||||
CFLAGS = -Wall -fpic -coverage -lm -std=c99 -ftest-coverage -fprofile-arcs
|
||||
|
||||
rngs.o: rngs.h rngs.c
|
||||
gcc -c rngs.c -g $(CFLAGS)
|
||||
|
||||
dominion.o: dominion.h dominion.c rngs.o
|
||||
gcc -c dominion.c -g $(CFLAGS)
|
||||
|
||||
playdom: dominion.o playdom.c
|
||||
gcc -o playdom playdom.c -g dominion.o rngs.o $(CFLAGS)
|
||||
|
||||
testDrawCard: testDrawCard.c dominion.o rngs.o
|
||||
gcc -o testDrawCard -g testDrawCard.c dominion.o rngs.o $(CFLAGS)
|
||||
|
||||
badTestDrawCard: badTestDrawCard.c dominion.o rngs.o
|
||||
gcc -o badTestDrawCard -g badTestDrawCard.c dominion.o rngs.o $(CFLAGS)
|
||||
|
||||
testBuyCard: testDrawCard.c dominion.o rngs.o
|
||||
gcc -o testDrawCard -g testDrawCard.c dominion.o rngs.o $(CFLAGS)
|
||||
|
||||
testAll: dominion.o testSuite.c
|
||||
gcc -o testSuite testSuite.c -g dominion.o rngs.o $(CFLAGS)
|
||||
|
||||
interface.o: interface.h interface.c
|
||||
gcc -c interface.c -g $(CFLAGS)
|
||||
|
||||
runtests: testDrawCard
|
||||
./testDrawCard &> unittestresult.out
|
||||
gcov dominion.c >> unittestresult.out
|
||||
cat dominion.c.gcov >> unittestresult.out
|
||||
|
||||
|
||||
player: player.c interface.o
|
||||
gcc -o player player.c -g dominion.o rngs.o interface.o $(CFLAGS)
|
||||
|
||||
all: playdom player testDrawCard testBuyCard badTestDrawCard
|
||||
|
||||
unittestresults.out:
|
||||
echo "Compiling and running all tests....." > unittestresults.out
|
||||
|
||||
gcc -o unittest1 unittest1.c dominion.c rngs.c -g $(CFLAGS)
|
||||
echo "Running Unittest1...." >> unittestresults.out
|
||||
./unittest1 >> unittestresults.out
|
||||
gcov dominion.c >> unittestresults.out
|
||||
cat dominion.c.gcov >> unittestresults.out
|
||||
cat dominion.c.gcov >> unittest1.gcov
|
||||
|
||||
echo "######################################" >> unittestresults.out
|
||||
echo "######################################" >> unittestresults.out
|
||||
|
||||
gcc -o unittest2 unittest2.c dominion.c rngs.c -g $(CFLAGS)
|
||||
echo "Running Unittest2...." >> unittestresults.out
|
||||
./unittest2 >> unittestresults.out
|
||||
gcov dominion.c >> unittestresults.out
|
||||
cat dominion.c.gcov >> unittestresults.out
|
||||
cat dominion.c.gcov >> unittest2.gcov
|
||||
|
||||
echo "######################################" >> unittestresults.out
|
||||
echo "######################################" >> unittestresults.out
|
||||
|
||||
gcc -o unittest3 unittest3.c dominion.c rngs.c -g $(CFLAGS)
|
||||
echo "Running Unittest3...." >> unittestresults.out
|
||||
./unittest3 >> unittestresults.out
|
||||
gcov dominion.c >> unittestresults.out
|
||||
cat dominion.c.gcov >> unittestresults.out
|
||||
cat dominion.c.gcov >> unittest3.gcov
|
||||
|
||||
echo "######################################" >> unittestresults.out
|
||||
echo "######################################" >> unittestresults.out
|
||||
|
||||
gcc -o unittest4 unittest4.c dominion.c rngs.c -g $(CFLAGS)
|
||||
echo "Running Unittest4...." >> unittestresults.out
|
||||
./unittest4 >> unittestresults.out
|
||||
gcov dominion.c >> unittestresults.out
|
||||
cat dominion.c.gcov >> unittestresults.out
|
||||
cat dominion.c.gcov >> unittest4.gcov
|
||||
|
||||
echo "######################################" >> unittestresults.out
|
||||
echo "######################################" >> unittestresults.out
|
||||
|
||||
gcc -o cardtest1 cardtest1.c dominion.c rngs.c -g $(CFLAGS)
|
||||
echo "Running Cardtest1...." >> unittestresults.out
|
||||
./cardtest1 >> unittestresults.out
|
||||
gcov dominion.c >> unittestresults.out
|
||||
cat dominion.c.gcov >> unittestresults.out
|
||||
cat dominion.c.gcov >> cardtest1.gcov
|
||||
|
||||
echo "######################################" >> unittestresults.out
|
||||
echo "######################################" >> unittestresults.out
|
||||
|
||||
gcc -o cardtest2 cardtest2.c dominion.c rngs.c -g $(CFLAGS)
|
||||
echo "Running Cardtest2...." >> unittestresults.out
|
||||
./cardtest2 >> unittestresults.out
|
||||
gcov dominion.c >> unittestresults.out
|
||||
cat dominion.c.gcov >> unittestresults.out
|
||||
cat dominion.c.gcov >> cardtest2.gcov
|
||||
|
||||
echo "######################################" >> unittestresults.out
|
||||
echo "######################################" >> unittestresults.out
|
||||
|
||||
gcc -o cardtest3 cardtest3.c dominion.c rngs.c -g $(CFLAGS)
|
||||
echo "Running Cardtest3...." >> unittestresults.out
|
||||
./cardtest3 >> unittestresults.out
|
||||
gcov dominion.c >> unittestresults.out
|
||||
cat dominion.c.gcov >> unittestresults.out
|
||||
cat dominion.c.gcov >> cardtest3.gcov
|
||||
|
||||
echo "######################################" >> unittestresults.out
|
||||
echo "######################################" >> unittestresults.out
|
||||
|
||||
gcc -o cardtest4 cardtest4.c dominion.c rngs.c -g $(CFLAGS)
|
||||
echo "Running Cardtest4...." >> unittestresults.out
|
||||
./cardtest4 >> unittestresults.out
|
||||
gcov dominion.c >> unittestresults.out
|
||||
cat dominion.c.gcov >> unittestresults.out
|
||||
cat dominion.c.gcov >> cardtest4.gcov
|
||||
|
||||
randomtests:
|
||||
gcc -o randomtestadventurer randomtestadventurer.c dominion.c rngs.c -g $(CFLAGS)
|
||||
./randomtestadventurer 29378 > randomtestadventurer.out
|
||||
gcov dominion.c >> randomtestadventurer.out
|
||||
cat dominion.c.gcov >> randomtestadventurer.out
|
||||
|
||||
gcc -o randomtestcard1 randomtestcard1.c dominion.c rngs.c -g $(CFLAGS)
|
||||
./randomtestcard1 29378 > randomtestcard1.out
|
||||
gcov dominion.c >> randomtestcard1.out
|
||||
cat dominion.c.gcov >> randomtestcard1.out
|
||||
|
||||
gcc -o randomtestcard2 randomtestcard2.c dominion.c rngs.c -g $(CFLAGS)
|
||||
./randomtestcard2 29378 > randomtestcard2.out
|
||||
gcov dominion.c >> randomtestcard2.out
|
||||
cat dominion.c.gcov >> randomtestcard2.out
|
||||
|
||||
buggytests:
|
||||
gcc -o cardtest2 cardtest2.c dominion.c rngs.c -g $(CFLAGS)
|
||||
|
||||
clean:
|
||||
rm -f *.o playdom.exe playdom test.exe test player player.exe testInit testInit.exe *.gcov *.gcda *.gcno *.so *.out
|
||||
rm -f randomtestadventurer randomtestcard1 randomtestcard2
|
||||
@@ -0,0 +1,44 @@
|
||||
#include "dominion.h"
|
||||
#include "dominion_helpers.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include "rngs.h"
|
||||
|
||||
#define DEBUG 0
|
||||
#define NOISY_TEST 1
|
||||
|
||||
int checkDrawCard(int p, struct gameState *post) {
|
||||
int r;
|
||||
|
||||
r = drawCard (p, post);
|
||||
}
|
||||
|
||||
int main () {
|
||||
|
||||
int i, n, r, p, deckCount, discardCount, handCount;
|
||||
|
||||
int k[10] = {adventurer, council_room, feast, gardens, mine,
|
||||
remodel, smithy, village, baron, great_hall};
|
||||
|
||||
struct gameState G;
|
||||
|
||||
printf ("Testing drawCard.\n");
|
||||
|
||||
printf ("RANDOM TESTS.\n");
|
||||
|
||||
SelectStream(2);
|
||||
PutSeed(3);
|
||||
|
||||
for (n = 0; n < 2000; n++) {
|
||||
for (i = 0; i < sizeof(struct gameState); i++) {
|
||||
((char*)&G)[i] = floor(Random() * 256);
|
||||
}
|
||||
p = floor(Random() * 1000);
|
||||
checkDrawCard(p, &G);
|
||||
}
|
||||
|
||||
printf ("ALL TESTS OK\n");
|
||||
|
||||
exit(0);
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
#include "dominion.h"
|
||||
#include "dominion_helpers.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include "rngs.h"
|
||||
|
||||
#define DEBUG 0
|
||||
#define NOISY_TEST 1
|
||||
|
||||
int checkDrawCard(int p, struct gameState *post) {
|
||||
int r;
|
||||
|
||||
r = drawCard (p, post);
|
||||
|
||||
assert (r == 0);
|
||||
}
|
||||
|
||||
int main () {
|
||||
|
||||
int i, n, r, p, deckCount, discardCount, handCount;
|
||||
|
||||
int k[10] = {adventurer, council_room, feast, gardens, mine,
|
||||
remodel, smithy, village, baron, great_hall};
|
||||
|
||||
struct gameState G;
|
||||
|
||||
printf ("Testing drawCard.\n");
|
||||
|
||||
printf ("RANDOM TESTS.\n");
|
||||
|
||||
SelectStream(2);
|
||||
PutSeed(3);
|
||||
|
||||
for (n = 0; n < 2000; n++) {
|
||||
for (i = 0; i < sizeof(struct gameState); i++) {
|
||||
((char*)&G)[i] = floor(Random() * 256);
|
||||
}
|
||||
p = floor(Random() * 2);
|
||||
G.deckCount[p] = floor(Random() * MAX_DECK);
|
||||
G.discardCount[p] = floor(Random() * MAX_DECK);
|
||||
G.handCount[p] = floor(Random() * MAX_HAND);
|
||||
checkDrawCard(p, &G);
|
||||
}
|
||||
|
||||
printf ("ALL TESTS OK\n");
|
||||
|
||||
exit(0);
|
||||
|
||||
printf ("SIMPLE FIXED TESTS.\n");
|
||||
for (p = 0; p < 2; p++) {
|
||||
for (deckCount = 0; deckCount < 5; deckCount++) {
|
||||
for (discardCount = 0; discardCount < 5; discardCount++) {
|
||||
for (handCount = 0; handCount < 5; handCount++) {
|
||||
memset(&G, 23, sizeof(struct gameState));
|
||||
r = initializeGame(2, k, 1, &G);
|
||||
G.deckCount[p] = deckCount;
|
||||
memset(G.deck[p], 0, sizeof(int) * deckCount);
|
||||
G.discardCount[p] = discardCount;
|
||||
memset(G.discard[p], 0, sizeof(int) * discardCount);
|
||||
G.handCount[p] = handCount;
|
||||
memset(G.hand[p], 0, sizeof(int) * handCount);
|
||||
checkDrawCard(p, &G);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
/*
|
||||
* File: unittest1.c
|
||||
* Author: corwinperren
|
||||
*
|
||||
* Created on February 1, 2017, 9:02 PM
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "dominion.h"
|
||||
#include "dominion_helpers.h"
|
||||
#include "rngs.h"
|
||||
|
||||
int testing_assert(int expression);
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
struct gameState G;
|
||||
int k[10] = {adventurer, gardens, embargo, village, minion, mine, cutpurse,
|
||||
sea_hag, tribute, smithy};
|
||||
|
||||
|
||||
|
||||
unsigned int arbitrary_hand_count_max = MAX_HAND - 1;
|
||||
|
||||
for(int i = 0 ; i < 4 ; i++){
|
||||
initializeGame(4, k, 65432, &G);
|
||||
G.deckCount[i] = MAX_DECK;
|
||||
G.whoseTurn = i;
|
||||
|
||||
for(int j = 0 ; j < arbitrary_hand_count_max ; j++){
|
||||
int hand_count = G.handCount[i];
|
||||
int num_actions = G.numActions;
|
||||
|
||||
playGreat_Hall(&G, j);
|
||||
testing_assert(G.handCount[i] == hand_count);
|
||||
testing_assert(G.numActions == num_actions + 1);
|
||||
|
||||
for(int j = 0 ; j < G.handCount[i] ; j++){
|
||||
testing_assert((G.hand[i][j] >= curse) && (G.hand[i][j] <= treasure_map));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// printf("Hand: %d\n", G.handCount[0]);
|
||||
// drawCard(0, &G);
|
||||
// printf("Hand: %d\n", G.handCount[0]);
|
||||
// G.numActions++;
|
||||
// discardCard(0, 0, &G, 0);
|
||||
// printf("Hand: %d\n\n", G.handCount[0]);
|
||||
//
|
||||
// printf("Hand: %d\n", G.handCount[0]);
|
||||
// playGreat_Hall(&G, 0);
|
||||
// printf("Hand: %d\n\n", G.handCount[0]);
|
||||
|
||||
return (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
int testing_assert(int expression) {
|
||||
if (expression) {
|
||||
printf("TEST SUCCEEDED!\n");
|
||||
return 1;
|
||||
} else {
|
||||
printf("TEST FAILED!\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
/*
|
||||
* File: unittest1.c
|
||||
* Author: corwinperren
|
||||
*
|
||||
* Created on February 1, 2017, 9:02 PM
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "dominion.h"
|
||||
#include "dominion_helpers.h"
|
||||
#include "rngs.h"
|
||||
|
||||
int testing_assert(int expression, int should_print);
|
||||
|
||||
long sucesses = 0;
|
||||
long failures = 0;
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
struct gameState G, G_copy;
|
||||
int k[10] = {adventurer, gardens, embargo, village, minion, mine, cutpurse,
|
||||
sea_hag, tribute, smithy};
|
||||
|
||||
|
||||
unsigned int arbitrary_hand_count_max = MAX_HAND - 3;
|
||||
|
||||
for(int l = 0 ; l < 4 ; l++){
|
||||
for(int i = 1 ; i < arbitrary_hand_count_max ; i++){
|
||||
initializeGame(4, k, 65432, &G);
|
||||
G.handCount[0] = arbitrary_hand_count_max;
|
||||
G.whoseTurn = l;
|
||||
|
||||
G_copy = G;
|
||||
|
||||
drawCard(0, &G_copy);
|
||||
drawCard(0, &G_copy);
|
||||
drawCard(0, &G_copy);
|
||||
discardCard(i, l, &G_copy, 0);
|
||||
|
||||
playSmithy(&G, i);
|
||||
|
||||
testing_assert(G.handCount[l] == G_copy.handCount[l], 0);
|
||||
|
||||
for(int j = 0 ; j < arbitrary_hand_count_max ; j++){
|
||||
testing_assert((G.hand[l][j] >= curse) && (G.hand[l][j] <= treasure_map), 0);
|
||||
testing_assert((G_copy.hand[l][j] >= curse) && (G_copy.hand[l][j] <= treasure_map), 0);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
printf("Run complete!\n");
|
||||
printf("SUCCESSES: %ld\n", sucesses);
|
||||
|
||||
if(failures > 0){
|
||||
printf("Some tests failed!!!\n");
|
||||
printf("FAILURES: %ld\n", failures);
|
||||
}
|
||||
|
||||
return (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
int testing_assert(int expression, int should_print) {
|
||||
if (expression) {
|
||||
if(should_print){
|
||||
printf("TEST SUCCEEDED!\n");
|
||||
}
|
||||
sucesses++;
|
||||
return 1;
|
||||
} else {
|
||||
if(should_print){
|
||||
printf("TEST FAILED!\n");
|
||||
}
|
||||
failures++;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
/*
|
||||
* File: unittest1.c
|
||||
* Author: corwinperren
|
||||
*
|
||||
* Created on February 1, 2017, 9:02 PM
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "dominion.h"
|
||||
#include "dominion_helpers.h"
|
||||
#include "rngs.h"
|
||||
|
||||
int testing_assert(int expression);
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
struct gameState G;
|
||||
int k[10] = {adventurer, gardens, embargo, village, minion, mine, cutpurse,
|
||||
sea_hag, tribute, smithy};
|
||||
|
||||
unsigned int arbitrary_hand_count_max = MAX_HAND - 2;
|
||||
|
||||
for(int l = 0 ; l < 4 ; l++){
|
||||
for(int i = 1 ; i < arbitrary_hand_count_max ; i++){
|
||||
initializeGame(4, k, 65432, &G);
|
||||
G.handCount[l] = arbitrary_hand_count_max;
|
||||
G.whoseTurn = l;
|
||||
|
||||
playAdventurer(&G);
|
||||
|
||||
testing_assert(G.handCount[l] == arbitrary_hand_count_max + 2);
|
||||
testing_assert((G.hand[l][G.handCount[l] - 1] >= copper) && (G.hand[l][G.handCount[l] - 1] <= gold));
|
||||
testing_assert((G.hand[l][G.handCount[l] - 2] >= copper) && (G.hand[l][G.handCount[l] - 2] <= gold));
|
||||
|
||||
initializeGame(4, k, 65432, &G);
|
||||
G.handCount[l] = arbitrary_hand_count_max;
|
||||
G.whoseTurn = l;
|
||||
G.deckCount[l] = 0;
|
||||
|
||||
for(int m = 0 ; m < MAX_DECK ; m += 3){
|
||||
G.discard[l][m] = copper;
|
||||
G.discard[l][m + 1] = silver;
|
||||
G.discard[l][m + 2] = gold;
|
||||
G.discardCount[l] += 3;
|
||||
}
|
||||
|
||||
|
||||
playAdventurer(&G);
|
||||
|
||||
testing_assert(G.handCount[l] == arbitrary_hand_count_max + 2);
|
||||
testing_assert((G.hand[l][G.handCount[l] - 1] >= copper) && (G.hand[l][G.handCount[l] - 1] <= gold));
|
||||
testing_assert((G.hand[l][G.handCount[l] - 2] >= copper) && (G.hand[l][G.handCount[l] - 2] <= gold));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
return (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
int testing_assert(int expression) {
|
||||
if (expression) {
|
||||
printf("TEST SUCCEEDED!\n");
|
||||
return 1;
|
||||
} else {
|
||||
printf("TEST FAILED!\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
/*
|
||||
* File: unittest1.c
|
||||
* Author: corwinperren
|
||||
*
|
||||
* Created on February 1, 2017, 9:02 PM
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "dominion.h"
|
||||
#include "dominion_helpers.h"
|
||||
#include "rngs.h"
|
||||
|
||||
int testing_assert(int expression);
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
struct gameState G;
|
||||
int k[10] = {adventurer, gardens, embargo, village, minion, mine, cutpurse,
|
||||
sea_hag, tribute, smithy};
|
||||
|
||||
|
||||
unsigned int arbitrary_hand_count_max = MAX_HAND - 3;
|
||||
|
||||
for(int l = 0 ; l < 4 ; l++){
|
||||
for(int i = 1 ; i < arbitrary_hand_count_max ; i++){
|
||||
initializeGame(4, k, 65432, &G);
|
||||
G.handCount[0] = arbitrary_hand_count_max;
|
||||
G.whoseTurn = l;
|
||||
|
||||
int outpost_before = G.outpostPlayed;
|
||||
int handcount_before = G.handCount[l];
|
||||
playOutpost(&G, i);
|
||||
|
||||
testing_assert(G.outpostPlayed == outpost_before + 1);
|
||||
testing_assert(G.handCount[l] == handcount_before - 1);
|
||||
}
|
||||
}
|
||||
|
||||
return (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
int testing_assert(int expression) {
|
||||
if (expression) {
|
||||
printf("TEST SUCCEEDED!\n");
|
||||
return 1;
|
||||
} else {
|
||||
printf("TEST FAILED!\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,142 @@
|
||||
#ifndef _DOMINION_H
|
||||
#define _DOMINION_H
|
||||
|
||||
// Code from various sources, baseline from Kristen Bartosz
|
||||
|
||||
#define MAX_HAND 500
|
||||
#define MAX_DECK 500
|
||||
|
||||
#define MAX_PLAYERS 4
|
||||
|
||||
#define DEBUG 0
|
||||
|
||||
//Testing commit
|
||||
|
||||
/* http://dominion.diehrstraits.com has card texts */
|
||||
/* http://dominion.isotropic.org has other stuff */
|
||||
|
||||
/* hand# means index of a card in current active player's hand */
|
||||
|
||||
enum CARD
|
||||
{curse = 0,
|
||||
estate,
|
||||
duchy,
|
||||
province,
|
||||
|
||||
copper,
|
||||
silver,
|
||||
gold,
|
||||
|
||||
adventurer,
|
||||
/* If no/only 1 treasure found, stop when full deck seen */
|
||||
council_room,
|
||||
feast, /* choice1 is supply # of card gained) */
|
||||
gardens,
|
||||
mine, /* choice1 is hand# of money to trash, choice2 is supply# of
|
||||
money to put in hand */
|
||||
remodel, /* choice1 is hand# of card to remodel, choice2 is supply# */
|
||||
smithy,
|
||||
village,
|
||||
|
||||
baron, /* choice1: boolean for discard of estate */
|
||||
/* Discard is always of first (lowest index) estate */
|
||||
great_hall,
|
||||
minion, /* choice1: 1 = +2 coin, 2 = redraw */
|
||||
steward, /* choice1: 1 = +2 card, 2 = +2 coin, 3 = trash 2 (choice2,3) */
|
||||
tribute,
|
||||
|
||||
ambassador, /* choice1 = hand#, choice2 = number to return to supply */
|
||||
cutpurse,
|
||||
embargo, /* choice1 = supply# */
|
||||
outpost,
|
||||
salvager, /* choice1 = hand# to trash */
|
||||
sea_hag,
|
||||
treasure_map
|
||||
};
|
||||
|
||||
struct gameState {
|
||||
int numPlayers; //number of players
|
||||
int supplyCount[treasure_map+1]; //this is the amount of a specific type of card given a specific number.
|
||||
int embargoTokens[treasure_map+1];
|
||||
int outpostPlayed;
|
||||
int outpostTurn;
|
||||
int whoseTurn;
|
||||
int phase;
|
||||
int numActions; /* Starts at 1 each turn */
|
||||
int coins; /* Use as you see fit! */
|
||||
int numBuys; /* Starts at 1 each turn */
|
||||
int hand[MAX_PLAYERS][MAX_HAND];
|
||||
int handCount[MAX_PLAYERS];
|
||||
int deck[MAX_PLAYERS][MAX_DECK];
|
||||
int deckCount[MAX_PLAYERS];
|
||||
int discard[MAX_PLAYERS][MAX_DECK];
|
||||
int discardCount[MAX_PLAYERS];
|
||||
int playedCards[MAX_DECK];
|
||||
int playedCardCount;
|
||||
};
|
||||
|
||||
/* All functions return -1 on failure, and DO NOT CHANGE GAME STATE;
|
||||
unless specified for other return, return 0 on success */
|
||||
|
||||
struct gameState* newGame();
|
||||
|
||||
int* kingdomCards(int k1, int k2, int k3, int k4, int k5, int k6, int k7,
|
||||
int k8, int k9, int k10);
|
||||
|
||||
int initializeGame(int numPlayers, int kingdomCards[10], int randomSeed,
|
||||
struct gameState *state);
|
||||
/* Responsible for initializing all supplies, and shuffling deck and
|
||||
drawing starting hands for all players. Check that 10 cards selected
|
||||
are in fact (different) kingdom cards, and that numPlayers is valid.
|
||||
|
||||
Cards not in game should initialize supply position to -1 */
|
||||
|
||||
int shuffle(int player, struct gameState *state);
|
||||
/* Assumes all cards are now in deck array (or hand/played): discard is
|
||||
empty */
|
||||
|
||||
int playCard(int handPos, int choice1, int choice2, int choice3,
|
||||
struct gameState *state);
|
||||
/* Play card with index handPos from current player's hand */
|
||||
|
||||
int buyCard(int supplyPos, struct gameState *state);
|
||||
/* Buy card with supply index supplyPos */
|
||||
|
||||
int numHandCards(struct gameState *state);
|
||||
/* How many cards current player has in hand */
|
||||
|
||||
int handCard(int handNum, struct gameState *state);
|
||||
/* enum value of indexed card in player's hand */
|
||||
|
||||
int supplyCount(int card, struct gameState *state);
|
||||
/* How many of given card are left in supply */
|
||||
|
||||
int fullDeckCount(int player, int card, struct gameState *state);
|
||||
/* Here deck = hand + discard + deck */
|
||||
|
||||
int whoseTurn(struct gameState *state);
|
||||
|
||||
int endTurn(struct gameState *state);
|
||||
/* Must do phase C and advance to next player; do not advance whose turn
|
||||
if game is over */
|
||||
|
||||
int isGameOver(struct gameState *state);
|
||||
|
||||
int scoreFor(int player, struct gameState *state);
|
||||
/* Negative here does not mean invalid; scores may be negative,
|
||||
-9999 means invalid input */
|
||||
|
||||
int getWinners(int players[MAX_PLAYERS], struct gameState *state);
|
||||
/* Set array position of each player who won (remember ties!) to
|
||||
1, others to 0 */
|
||||
|
||||
int playAdventurer(struct gameState *state);
|
||||
int playSmithy(struct gameState *state, int handPos);
|
||||
int playVillage(struct gameState *state, int handPos);
|
||||
int playFeast(struct gameState *state, int choice1);
|
||||
int playCouncil_Room(struct gameState *state, int handPos);
|
||||
int playGreat_Hall(struct gameState *state, int handPos);
|
||||
int playOutpost(struct gameState *state, int handPos);
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,15 @@
|
||||
#ifndef _DOMINION_HELPERS_H
|
||||
#define _DOMINION_HELPERS_H
|
||||
|
||||
#include "dominion.h"
|
||||
|
||||
int drawCard(int player, struct gameState *state);
|
||||
int updateCoins(int player, struct gameState *state, int bonus);
|
||||
int discardCard(int handPos, int currentPlayer, struct gameState *state,
|
||||
int trashFlag);
|
||||
int gainCard(int supplyPos, struct gameState *state, int toFlag, int player);
|
||||
int getCost(int cardNumber);
|
||||
int cardEffect(int card, int choice1, int choice2, int choice3,
|
||||
struct gameState *state, int handPos, int *bonus);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,363 @@
|
||||
/* Interactive Dominion Interface
|
||||
|
||||
Sam Heinith CS362
|
||||
1/26/2010
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "rngs.h"
|
||||
#include "interface.h"
|
||||
#include "dominion.h"
|
||||
|
||||
|
||||
void cardNumToName(int card, char *name){
|
||||
switch(card){
|
||||
case curse: strcpy(name,"Curse");
|
||||
break;
|
||||
case estate: strcpy(name,"Estate");
|
||||
break;
|
||||
case duchy: strcpy(name,"Duchy");
|
||||
break;
|
||||
case province: strcpy(name,"Province");
|
||||
break;
|
||||
case copper: strcpy(name,"Copper");
|
||||
break;
|
||||
case silver: strcpy(name,"Silver");
|
||||
break;
|
||||
case gold: strcpy(name,"Gold");
|
||||
break;
|
||||
case adventurer: strcpy(name,"Adventurer");
|
||||
break;
|
||||
case council_room: strcpy(name,"Council Room");
|
||||
break;
|
||||
case feast: strcpy(name,"Feast");
|
||||
break;
|
||||
case gardens: strcpy(name,"Gardens");
|
||||
break;
|
||||
case mine: strcpy(name,"Mine");
|
||||
break;
|
||||
case remodel: strcpy(name,"Remodel");
|
||||
break;
|
||||
case smithy: strcpy(name,"Smithy");
|
||||
break;
|
||||
case village: strcpy(name,"Village");
|
||||
break;
|
||||
case baron: strcpy(name,"Baron");
|
||||
break;
|
||||
case great_hall: strcpy(name,"Great Hall");
|
||||
break;
|
||||
case minion: strcpy(name,"Minion");
|
||||
break;
|
||||
case steward: strcpy(name,"Steward");
|
||||
break;
|
||||
case tribute: strcpy(name,"Tribute");
|
||||
break;
|
||||
case ambassador: strcpy(name,"Ambassador");
|
||||
break;
|
||||
case cutpurse: strcpy(name,"Cutpurse");
|
||||
break;
|
||||
case embargo: strcpy(name,"Embargo");
|
||||
break;
|
||||
case outpost: strcpy(name,"Outpost");
|
||||
break;
|
||||
case salvager: strcpy(name,"Salvager");
|
||||
break;
|
||||
case sea_hag: strcpy(name,"Sea Hag");
|
||||
break;
|
||||
case treasure_map: strcpy(name,"Treasure Map");
|
||||
break;
|
||||
|
||||
default: strcpy(name,"?");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
int getCardCost(int card) {
|
||||
int cost;
|
||||
switch(card) {
|
||||
case curse: cost = CURSE_COST;
|
||||
break;
|
||||
case estate: cost = ESTATE_COST;
|
||||
break;
|
||||
case duchy: cost = DUCHY_COST;
|
||||
break;
|
||||
case province: cost = PROVINCE_COST;
|
||||
break;
|
||||
case copper: cost = COPPER_COST;
|
||||
break;
|
||||
case silver: cost = SILVER_COST;
|
||||
break;
|
||||
case gold: cost = GOLD_COST;
|
||||
break;
|
||||
case adventurer: cost = ADVENTURER_COST;
|
||||
break;
|
||||
case council_room: cost = COUNCIL_ROOM_COST;
|
||||
break;
|
||||
case feast: cost = FEAST_COST;
|
||||
break;
|
||||
case gardens: cost = GARDEN_COST;
|
||||
break;
|
||||
case mine: cost = MINE_COST;
|
||||
break;
|
||||
case remodel: cost = REMODEL_COST;
|
||||
break;
|
||||
case smithy: cost = SMITHY_COST;
|
||||
break;
|
||||
case village: cost = VILLAGE_COST;
|
||||
break;
|
||||
case baron: cost = BARON_COST;
|
||||
break;
|
||||
case great_hall: cost = GREAT_HALL_COST;
|
||||
break;
|
||||
case minion: cost = MINION_COST;
|
||||
break;
|
||||
case steward: cost = STEWARD_COST;
|
||||
break;
|
||||
case tribute: cost = TRIBUTE_COST;
|
||||
break;
|
||||
case ambassador: cost = AMBASSADOR_COST;
|
||||
break;
|
||||
case cutpurse: cost = CUTPURSE_COST;
|
||||
break;
|
||||
case embargo: cost = EMBARGO_COST;
|
||||
break;
|
||||
case outpost: cost = OUTPOST_COST;
|
||||
break;
|
||||
case salvager: cost = SALVAGER_COST;
|
||||
break;
|
||||
case sea_hag: cost = SEA_HAG_COST;
|
||||
break;
|
||||
case treasure_map: cost = TREASURE_MAP_COST;
|
||||
break;
|
||||
default: cost = ONETHOUSAND;
|
||||
}
|
||||
return cost;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void printHand(int player, struct gameState *game) {
|
||||
int handCount = game->handCount[player];
|
||||
int handIndex;
|
||||
printf("Player %d's hand:\n", player);
|
||||
if(handCount > 0) printf("# Card\n");
|
||||
for(handIndex = 0; handIndex < handCount; handIndex++) {
|
||||
int card = game->hand[player][handIndex];
|
||||
char name[MAX_STRING_LENGTH];
|
||||
cardNumToName(card, name);
|
||||
printf("%-2d %-13s\n", handIndex, name);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
void printDeck(int player, struct gameState *game) {
|
||||
int deckCount = game->deckCount[player];
|
||||
int deckIndex;
|
||||
printf("Player %d's deck: \n", player);
|
||||
if(deckCount > 0) printf("# Card\n");
|
||||
for(deckIndex = 0; deckIndex < deckCount; deckIndex++) {
|
||||
int card = game->deck[player][deckIndex];
|
||||
char name[MAX_STRING_LENGTH];
|
||||
cardNumToName(card, name);
|
||||
printf("%-2d %-13s\n", deckIndex, name);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void printPlayed(int player, struct gameState *game) {
|
||||
int playedCount = game->playedCardCount;
|
||||
int playedIndex;
|
||||
printf("Player %d's played cards: \n", player);
|
||||
if(playedCount > 0) printf("# Card\n");
|
||||
for(playedIndex = 0; playedIndex < playedCount; playedIndex++) {
|
||||
int card = game->playedCards[playedIndex];
|
||||
char name[MAX_STRING_LENGTH];
|
||||
cardNumToName(card, name);
|
||||
printf("%-2d %-13s \n", playedIndex, name);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
void printDiscard(int player, struct gameState *game) {
|
||||
int discardCount = game->discardCount[player];
|
||||
int discardIndex;
|
||||
printf("Player %d's discard: \n", player);
|
||||
if(discardCount > 0) printf("# Card\n");
|
||||
for(discardIndex = 0; discardIndex < discardCount; discardIndex++) {
|
||||
int card = game->discard[player][discardIndex];
|
||||
char name[MAX_STRING_LENGTH];
|
||||
cardNumToName(card, name);
|
||||
printf("%-2d %-13s \n", discardIndex, name);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void printSupply(struct gameState *game) {
|
||||
int cardNum, cardCost, cardCount;
|
||||
char name[MAX_STRING_LENGTH];
|
||||
printf("# Card Cost Copies\n");
|
||||
for(cardNum = 0; cardNum < NUM_TOTAL_K_CARDS; cardNum++){
|
||||
cardCount = game->supplyCount[cardNum];
|
||||
if(cardCount == -1) continue;
|
||||
cardNumToName(cardNum, name);
|
||||
cardCost = getCardCost(cardNum);
|
||||
printf("%-2d %-13s %-5d %-5d", cardNum, name, cardCost, cardCount);
|
||||
printf("\n");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
||||
void printState(struct gameState *game) {
|
||||
int numActions = game->numActions;
|
||||
int numCoins = game->coins;
|
||||
int numBuys = game->numBuys;
|
||||
int currentPlayer = game->whoseTurn;
|
||||
int phase = game->phase;
|
||||
char phaseName[MAX_STRING_LENGTH];
|
||||
phaseNumToName(phase,phaseName);
|
||||
printf("Player %d:\n%s phase\n%d actions\n%d coins\n%d buys\n\n", currentPlayer, phaseName, numActions, numCoins, numBuys);
|
||||
}
|
||||
|
||||
void printScores(struct gameState *game) {
|
||||
int playerNum, score[MAX_PLAYERS];
|
||||
int numPlayers = game->numPlayers;
|
||||
for(playerNum = 0; playerNum < numPlayers; playerNum++) {
|
||||
score[playerNum] = scoreFor(playerNum,game);
|
||||
printf("Player %d has a score of %d\n", playerNum, score[playerNum]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void printHelp(void) {
|
||||
printf("Commands are: \n\
|
||||
add [Supply Card Number] - add any card to your hand (teh hacks)\n\
|
||||
buy [Supply Card Number] - buy a card at supply position\n\
|
||||
end - end your turn\n\
|
||||
init [Number of Players] [Number of Bots] - initialize the game\n\
|
||||
num - print number of cards in your hand\n\
|
||||
play [Hand Index] [Choice] [Choice] [Choice] - play a card from your hand\n\
|
||||
resign - end the game showing the current scores\n\
|
||||
show - show your current hand\n\
|
||||
stat - show your turn's status\n\
|
||||
supp - show the supply\n\
|
||||
whos - whos turn\n\
|
||||
exit - exit the interface");
|
||||
printf("\n\n");
|
||||
|
||||
}
|
||||
|
||||
|
||||
void phaseNumToName(int phase, char *name) {
|
||||
switch(phase){
|
||||
case ACTION_PHASE: strcpy(name,"Action");
|
||||
break;
|
||||
case BUY_PHASE: strcpy(name,"Buy");
|
||||
break;
|
||||
case CLEANUP_PHASE: strcpy(name,"Cleanup");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int addCardToHand(int player, int card, struct gameState *game) {
|
||||
if(card >= adventurer && card < NUM_TOTAL_K_CARDS){
|
||||
int handTop = game->handCount[player];
|
||||
game->hand[player][handTop] = card;
|
||||
game->handCount[player]++;
|
||||
return SUCCESS;
|
||||
} else {
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void selectKingdomCards(int randomSeed, int kingCards[NUM_K_CARDS]) {
|
||||
int i, used, card, numSelected = 0;
|
||||
SelectStream(1);
|
||||
PutSeed((long)randomSeed);
|
||||
|
||||
|
||||
while(numSelected < NUM_K_CARDS) {
|
||||
used = FALSE;
|
||||
card = floor(Random() * NUM_TOTAL_K_CARDS);
|
||||
if(card < adventurer) continue;
|
||||
for(i = 0; i < numSelected; i++) {
|
||||
if(kingCards[i] == card) {
|
||||
used = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(used == TRUE) continue;
|
||||
kingCards[numSelected] = card;
|
||||
numSelected++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int countHandCoins(int player, struct gameState *game) {
|
||||
int card, index, coinage = 0;
|
||||
|
||||
for(index = 0; index < game->handCount[player]; index++) {
|
||||
card = game->hand[player][index];
|
||||
switch(card) {
|
||||
case copper: coinage += COPPER_VALUE;
|
||||
break;
|
||||
case silver: coinage += SILVER_VALUE;
|
||||
break;
|
||||
case gold: coinage += GOLD_VALUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return coinage;
|
||||
}
|
||||
|
||||
|
||||
void executeBotTurn(int player, int *turnNum, struct gameState *game) {
|
||||
int coins = countHandCoins(player, game);
|
||||
|
||||
printf("*****************Executing Bot Player %d Turn Number %d*****************\n", player, *turnNum);
|
||||
printSupply(game);
|
||||
//sleep(1); //Thinking...
|
||||
|
||||
if(coins >= PROVINCE_COST && supplyCount(province,game) > 0) {
|
||||
buyCard(province,game);
|
||||
printf("Player %d buys card Province\n\n", player);
|
||||
}
|
||||
else if(supplyCount(province,game) == 0 && coins >= DUCHY_COST ) {
|
||||
buyCard(duchy,game);
|
||||
printf("Player %d buys card Duchy\n\n", player);
|
||||
}
|
||||
else if(coins >= GOLD_COST && supplyCount(gold,game) > 0) {
|
||||
buyCard(gold,game);
|
||||
printf("Player %d buys card Gold\n\n", player);
|
||||
}
|
||||
else if(coins >= SILVER_COST && supplyCount(silver,game) > 0) {
|
||||
buyCard(silver,game);
|
||||
printf("Player %d buys card Silver\n\n", player);
|
||||
|
||||
}
|
||||
|
||||
|
||||
if(player == (game->numPlayers -1)) (*turnNum)++;
|
||||
endTurn(game);
|
||||
if(! isGameOver(game)) {
|
||||
int currentPlayer = whoseTurn(game);
|
||||
printf("Player %d's turn number %d\n\n", currentPlayer, (*turnNum));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
/* Interactive Dominion Interface
|
||||
|
||||
Sam Heinith CS362
|
||||
1/26/2010
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef _INTERFACE_H
|
||||
#define _INTERFACE_H
|
||||
|
||||
|
||||
|
||||
#include "dominion.h"
|
||||
|
||||
//Last card enum (Treasure map) card number plus one for the 0th card.
|
||||
#define NUM_TOTAL_K_CARDS (treasure_map + 1)
|
||||
#define NUM_K_CARDS 10
|
||||
#define NUM_V_CARDS_2 8
|
||||
#define NUM_V_CARDS_3or4 12
|
||||
#define NUM_C_CARDS_2 10
|
||||
#define NUM_C_CARDS_3 20
|
||||
#define NUM_C_CARDS_4 30
|
||||
#define NUM_COPPER 60
|
||||
#define NUM_SILVER 40
|
||||
#define NUM_GOLD 30
|
||||
#define UNUSED -1
|
||||
#define START_COPPER 7
|
||||
#define START_ESTATE 3
|
||||
#define HANDSIZE 5
|
||||
|
||||
#define COMPARE(string1, string2) strncmp(string1, string2, 4)
|
||||
#define MAX_STRING_LENGTH 32
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
#define SUCCESS 0
|
||||
#define FAILURE -1
|
||||
|
||||
#define MATCH 0
|
||||
#define WINNER 1
|
||||
#define NOT_WINNER 0
|
||||
|
||||
//The Game Phases
|
||||
#define ACTION_PHASE 0
|
||||
#define BUY_PHASE 1
|
||||
#define CLEANUP_PHASE 2
|
||||
|
||||
#define COPPER_VALUE 1
|
||||
#define SILVER_VALUE 2
|
||||
#define GOLD_VALUE 3
|
||||
|
||||
//From Dominion List Spoiler
|
||||
#define COPPER_COST 0
|
||||
#define SILVER_COST 3
|
||||
#define GOLD_COST 6
|
||||
#define ESTATE_COST 2
|
||||
#define DUCHY_COST 5
|
||||
#define PROVINCE_COST 8
|
||||
#define CURSE_COST 0
|
||||
#define ADVENTURER_COST 6
|
||||
#define COUNCIL_ROOM_COST 5
|
||||
#define FEAST_COST 4
|
||||
#define GARDEN_COST 4
|
||||
#define MINE_COST 5
|
||||
#define MONEYLENDER_COST 4
|
||||
#define REMODEL_COST 4
|
||||
#define SMITHY_COST 4
|
||||
#define VILLAGE_COST 3
|
||||
#define WOODCUTTER_COST 3
|
||||
#define BARON_COST 4
|
||||
#define GREAT_HALL_COST 3
|
||||
#define MINION_COST 5
|
||||
#define SHANTY_TOWN_COST 3
|
||||
#define STEWARD_COST 3
|
||||
#define TRIBUTE_COST 5
|
||||
#define WISHING_WELL_COST 3
|
||||
#define AMBASSADOR_COST 3
|
||||
#define CUTPURSE_COST 4
|
||||
#define EMBARGO_COST 2
|
||||
#define OUTPOST_COST 5
|
||||
#define SALVAGER_COST 4
|
||||
#define SEA_HAG_COST 4
|
||||
#define TREASURE_MAP_COST 4
|
||||
#define ONETHOUSAND 1000
|
||||
|
||||
|
||||
int addCardToHand(int player, int card, struct gameState *game);
|
||||
|
||||
int countHandCoins(int player, struct gameState *game);
|
||||
|
||||
|
||||
void executeBotTurn(int player, int *turnNum, struct gameState *game);
|
||||
|
||||
void phaseNumToName(int phase, char *name);
|
||||
void cardNumToName(int card, char *name);
|
||||
|
||||
int getCardCost(int card);
|
||||
|
||||
void printHelp(void);
|
||||
|
||||
void printHand(int player, struct gameState *game);
|
||||
|
||||
void printDeck(int player, struct gameState *game);
|
||||
|
||||
void printDiscard(int player, struct gameState *game);
|
||||
|
||||
void printPlayed(int player, struct gameState *game);
|
||||
|
||||
void printState(struct gameState *game);
|
||||
|
||||
void printSupply(struct gameState *game);
|
||||
|
||||
void printGameState(struct gameState *game);
|
||||
|
||||
void printScores(struct gameState *game);
|
||||
|
||||
void selectKingdomCards(int randomSeed, int kingdomCards[NUM_K_CARDS]);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
#include "dominion.h"
|
||||
#include <stdio.h>
|
||||
#include "rngs.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
int main (int argc, char** argv) {
|
||||
struct gameState G;
|
||||
int k[10] = {adventurer, gardens, embargo, village, minion, mine, cutpurse,
|
||||
sea_hag, tribute, smithy};
|
||||
|
||||
printf ("Starting game.\n");
|
||||
|
||||
initializeGame(2, k, atoi(argv[1]), &G);
|
||||
|
||||
int money = 0;
|
||||
int smithyPos = -1;
|
||||
int adventurerPos = -1;
|
||||
int i=0;
|
||||
|
||||
int numSmithies = 0;
|
||||
int numAdventurers = 0;
|
||||
|
||||
while (!isGameOver(&G)) {
|
||||
money = 0;
|
||||
smithyPos = -1;
|
||||
adventurerPos = -1;
|
||||
for (i = 0; i < numHandCards(&G); i++) {
|
||||
if (handCard(i, &G) == copper)
|
||||
money++;
|
||||
else if (handCard(i, &G) == silver)
|
||||
money += 2;
|
||||
else if (handCard(i, &G) == gold)
|
||||
money += 3;
|
||||
else if (handCard(i, &G) == smithy)
|
||||
smithyPos = i;
|
||||
else if (handCard(i, &G) == adventurer)
|
||||
adventurerPos = i;
|
||||
}
|
||||
|
||||
if (whoseTurn(&G) == 0) {
|
||||
if (smithyPos != -1) {
|
||||
printf("0: smithy played from position %d\n", smithyPos);
|
||||
playCard(smithyPos, -1, -1, -1, &G);
|
||||
printf("smithy played.\n");
|
||||
money = 0;
|
||||
i=0;
|
||||
while(i<numHandCards(&G)){
|
||||
if (handCard(i, &G) == copper){
|
||||
playCard(i, -1, -1, -1, &G);
|
||||
money++;
|
||||
}
|
||||
else if (handCard(i, &G) == silver){
|
||||
playCard(i, -1, -1, -1, &G);
|
||||
money += 2;
|
||||
}
|
||||
else if (handCard(i, &G) == gold){
|
||||
playCard(i, -1, -1, -1, &G);
|
||||
money += 3;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
if (money >= 8) {
|
||||
printf("0: bought province\n");
|
||||
buyCard(province, &G);
|
||||
}
|
||||
else if (money >= 6) {
|
||||
printf("0: bought gold\n");
|
||||
buyCard(gold, &G);
|
||||
}
|
||||
else if ((money >= 4) && (numSmithies < 2)) {
|
||||
printf("0: bought smithy\n");
|
||||
buyCard(smithy, &G);
|
||||
numSmithies++;
|
||||
}
|
||||
else if (money >= 3) {
|
||||
printf("0: bought silver\n");
|
||||
buyCard(silver, &G);
|
||||
}
|
||||
|
||||
printf("0: end turn\n");
|
||||
endTurn(&G);
|
||||
}
|
||||
else {
|
||||
if (adventurerPos != -1) {
|
||||
printf("1: adventurer played from position %d\n", adventurerPos);
|
||||
playCard(adventurerPos, -1, -1, -1, &G);
|
||||
money = 0;
|
||||
i=0;
|
||||
while(i<numHandCards(&G)){
|
||||
if (handCard(i, &G) == copper){
|
||||
playCard(i, -1, -1, -1, &G);
|
||||
money++;
|
||||
}
|
||||
else if (handCard(i, &G) == silver){
|
||||
playCard(i, -1, -1, -1, &G);
|
||||
money += 2;
|
||||
}
|
||||
else if (handCard(i, &G) == gold){
|
||||
playCard(i, -1, -1, -1, &G);
|
||||
money += 3;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
if (money >= 8) {
|
||||
printf("1: bought province\n");
|
||||
buyCard(province, &G);
|
||||
}
|
||||
else if ((money >= 6) && (numAdventurers < 2)) {
|
||||
printf("1: bought adventurer\n");
|
||||
buyCard(adventurer, &G);
|
||||
numAdventurers++;
|
||||
}else if (money >= 6){
|
||||
printf("1: bought gold\n");
|
||||
buyCard(gold, &G);
|
||||
}
|
||||
else if (money >= 3){
|
||||
printf("1: bought silver\n");
|
||||
buyCard(silver, &G);
|
||||
}
|
||||
printf("1: endTurn\n");
|
||||
|
||||
endTurn(&G);
|
||||
}
|
||||
} // end of While
|
||||
|
||||
printf ("Finished game.\n");
|
||||
printf ("Player 0: %d\nPlayer 1: %d\n", scoreFor(0, &G), scoreFor(1, &G));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,216 @@
|
||||
/* Interactive Dominion Interface
|
||||
Version 7
|
||||
|
||||
Sam Heinith CS362
|
||||
Questions/Comments:
|
||||
heiniths@onid.orst.edu
|
||||
1/26/2010
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include "dominion.h"
|
||||
#include "interface.h"
|
||||
#include "rngs.h"
|
||||
|
||||
|
||||
int main2(int argc, char *argv[]) {
|
||||
//Default cards, as defined in playDom
|
||||
int k[10] = {adventurer, gardens, embargo, village, minion, mine, cutpurse, sea_hag, tribute, smithy};
|
||||
struct gameState g;
|
||||
initializeGame(2,k,1,&g);
|
||||
printf ("SUCCESSFUL INIT\n");
|
||||
getchar();
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
char *add = "add";
|
||||
char *buyC = "buy";
|
||||
char *endT = "end";
|
||||
char *exit = "exit";
|
||||
char *help = "help";
|
||||
char *init = "init";
|
||||
char *numH = "num";
|
||||
char *play = "play";
|
||||
char *resign = "resi";
|
||||
char *show = "show";
|
||||
char *stat = "stat";
|
||||
char *supply = "supp";
|
||||
char *whos = "whos";
|
||||
|
||||
char command[MAX_STRING_LENGTH];
|
||||
char line[MAX_STRING_LENGTH];
|
||||
char cardName[MAX_STRING_LENGTH];
|
||||
|
||||
//Array to hold bot presence
|
||||
int isBot[MAX_PLAYERS] = { 0, 0, 0, 0};
|
||||
|
||||
int players[MAX_PLAYERS];
|
||||
int playerNum;
|
||||
int outcome;
|
||||
int currentPlayer;
|
||||
int gameOver = FALSE;
|
||||
int gameStarted = FALSE;
|
||||
int turnNum = 0;
|
||||
|
||||
int randomSeed = atoi(argv[1]);
|
||||
|
||||
//Default cards, as defined in playDom
|
||||
int kCards[10] = {adventurer, gardens, embargo, village, minion, mine, cutpurse, sea_hag, tribute, smithy};
|
||||
|
||||
struct gameState g;
|
||||
struct gameState * game = &g;
|
||||
|
||||
memset(game,0,sizeof(struct gameState));
|
||||
|
||||
if(argc != 2){
|
||||
printf("Usage: player [integer random number seed]\n");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
if(randomSeed <= 0){
|
||||
printf("Usage: player [integer random number seed]\n");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
initializeGame(2,kCards,randomSeed,game);
|
||||
|
||||
printf("Please enter a command or \"help\" for commands\n");
|
||||
|
||||
|
||||
while(TRUE) {
|
||||
int arg0 = UNUSED;
|
||||
int arg1 = UNUSED;
|
||||
int arg2 = UNUSED;
|
||||
int arg3 = UNUSED;
|
||||
|
||||
outcome = FAILURE;
|
||||
strcpy(line,"");
|
||||
strcpy(command,"");
|
||||
strcpy(cardName,"");
|
||||
|
||||
currentPlayer = whoseTurn(game);
|
||||
|
||||
//If you are getting a seg fault comment this if block out
|
||||
gameOver = isGameOver(game);
|
||||
if(gameStarted == TRUE && gameOver == TRUE){
|
||||
printScores(game);
|
||||
getWinners(players, game);
|
||||
printf("After %d turns, the winner(s) are:\n", turnNum);
|
||||
for(playerNum = 0; playerNum < game->numPlayers; playerNum++){
|
||||
if(players[playerNum] == WINNER) printf("Player %d\n", playerNum);
|
||||
}
|
||||
for(playerNum = 0; playerNum < game->numPlayers; playerNum++){
|
||||
printHand(playerNum, game);
|
||||
printPlayed(playerNum, game);
|
||||
printDiscard(playerNum, game);
|
||||
printDeck(playerNum, game);
|
||||
}
|
||||
|
||||
break; //Exit out of the game/while loop
|
||||
}
|
||||
|
||||
|
||||
if(isBot[currentPlayer] == TRUE) {
|
||||
executeBotTurn(currentPlayer, &turnNum, game);
|
||||
continue;
|
||||
}
|
||||
|
||||
printf("$ ");
|
||||
fgets(line, MAX_STRING_LENGTH, stdin);
|
||||
sscanf(line, "%s %d %d %d %d", command, &arg0, &arg1, &arg2, &arg3);
|
||||
|
||||
|
||||
if(COMPARE(command, add) == 0) {
|
||||
outcome = addCardToHand(currentPlayer, arg0, game);
|
||||
cardNumToName(arg0, cardName);
|
||||
printf("Player %d adds %s to their hand\n\n", currentPlayer, cardName);
|
||||
} else
|
||||
if(COMPARE(command, buyC) == 0) {
|
||||
outcome = buyCard(arg0, game);
|
||||
cardNumToName(arg0, cardName);
|
||||
if(outcome == SUCCESS){
|
||||
printf("Player %d buys card %d, %s\n\n", currentPlayer, arg0, cardName);
|
||||
} else {
|
||||
printf("Player %d cannot buy card %d, %s\n\n", currentPlayer, arg0, cardName);
|
||||
}
|
||||
} else
|
||||
if(COMPARE(command, endT) == 0) {
|
||||
if(gameStarted == TRUE) {
|
||||
if(currentPlayer == (game->numPlayers -1)) turnNum++;
|
||||
endTurn(game);
|
||||
currentPlayer = whoseTurn(game);
|
||||
printf("Player %d's turn number %d\n\n", currentPlayer, turnNum);
|
||||
}
|
||||
|
||||
} else
|
||||
if(COMPARE(command, exit) == 0) {
|
||||
break;
|
||||
} else
|
||||
if(COMPARE(command, help) == 0) {
|
||||
printHelp();
|
||||
} else
|
||||
if(COMPARE(command, init) == 0) {
|
||||
int numHuman = arg0 - arg1;
|
||||
for(playerNum = numHuman; playerNum < arg0; playerNum++) {
|
||||
isBot[playerNum] = TRUE;
|
||||
}
|
||||
// selectKingdomCards(randomSeed, kCards); //Comment this out to use the default card set defined in playDom.
|
||||
outcome = initializeGame(arg0, kCards, randomSeed, game);
|
||||
printf("\n");
|
||||
if(outcome == SUCCESS){
|
||||
gameStarted = TRUE;
|
||||
currentPlayer = whoseTurn(game);
|
||||
printf("Player %d's turn number %d\n\n", currentPlayer, turnNum);
|
||||
}
|
||||
|
||||
} else
|
||||
if(COMPARE(command, numH) == 0) {
|
||||
int numCards = numHandCards(game);
|
||||
printf("There are %d cards in your hand.\n", numCards);
|
||||
} else
|
||||
if(COMPARE(command, play) == 0) {
|
||||
int card = handCard(arg0,game);
|
||||
outcome = playCard(arg0, arg1, arg2, arg3, game);
|
||||
cardNumToName(card, cardName);
|
||||
if(outcome == SUCCESS){
|
||||
printf("Player %d plays %s\n\n", currentPlayer, cardName);
|
||||
} else {
|
||||
printf("Player %d cannot play card %d\n\n", currentPlayer, arg0);
|
||||
}
|
||||
|
||||
} else
|
||||
if(COMPARE(command, resign) == 0) {
|
||||
endTurn(game);
|
||||
printScores(game);
|
||||
break;
|
||||
} else
|
||||
if(COMPARE(command, show) == 0) {
|
||||
if(gameStarted == FALSE) continue;
|
||||
printHand(currentPlayer, game);
|
||||
printPlayed(currentPlayer, game);
|
||||
//printDiscard(currentPlayer, game);
|
||||
//printDeck(currentPlayer, game);
|
||||
} else
|
||||
if(COMPARE(command, stat) == 0) {
|
||||
if(gameStarted == FALSE) continue;
|
||||
printState(game);
|
||||
} else
|
||||
if(COMPARE(command, supply) == 0) {
|
||||
printSupply(game);
|
||||
} else
|
||||
if(COMPARE(command, whos) == 0) {
|
||||
int playerNum = whoseTurn(game);
|
||||
printf("Player %d's turn\n", playerNum);
|
||||
}
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include "dominion.h"
|
||||
#include "dominion_helpers.h"
|
||||
#include "rngs.h"
|
||||
|
||||
int testing_assert(int expression, int should_print);
|
||||
|
||||
long sucesses = 0;
|
||||
long failures = 0;
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
// Get seed from command line arg and setup randomization or exit
|
||||
if(argc < 2){
|
||||
printf("Please enter a seed value for randomization.\n");
|
||||
printf("usage: %s [seed]\n", argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
long seed = atoi(argv[1]);
|
||||
|
||||
|
||||
SelectStream(1);
|
||||
PutSeed(seed);
|
||||
|
||||
// Game variables
|
||||
struct gameState G;
|
||||
int k[10] = {adventurer, gardens, embargo, village, minion, mine, cutpurse,
|
||||
sea_hag, tribute, smithy};
|
||||
|
||||
// Initialize the game
|
||||
initializeGame(4, k, seed, &G);
|
||||
|
||||
// Limiting variables
|
||||
unsigned int arbritray_num_tests = 100000;
|
||||
unsigned int arbitrary_hand_count_max = MAX_HAND - 2;
|
||||
|
||||
for(int z = 0 ; z < arbritray_num_tests ; z++){
|
||||
int turn = floor(Random() *MAX_PLAYERS);
|
||||
int starting_hand = floor(Random() * arbitrary_hand_count_max);
|
||||
|
||||
G.deckCount[turn] = MAX_DECK;
|
||||
G.discardCount[turn] = 0;
|
||||
|
||||
G.handCount[turn] = starting_hand;
|
||||
G.whoseTurn = turn;
|
||||
|
||||
playAdventurer(&G);
|
||||
|
||||
testing_assert(G.handCount[turn] == starting_hand + 2, 0);
|
||||
testing_assert((G.hand[turn][G.handCount[turn] - 1] >= copper) && (G.hand[turn][G.handCount[turn] - 1] <= gold), 0);
|
||||
testing_assert((G.hand[turn][G.handCount[turn] - 2] >= copper) && (G.hand[turn][G.handCount[turn] - 2] <= gold), 0);
|
||||
|
||||
|
||||
G.handCount[turn] = starting_hand;
|
||||
G.deckCount[turn] = 0;
|
||||
G.discardCount[turn] = 0;
|
||||
|
||||
for(int m = 0 ; m < MAX_DECK ; m++){
|
||||
int card = copper + floor(Random() * 2);
|
||||
|
||||
G.discard[turn][m] = card;
|
||||
G.discardCount[turn]++;
|
||||
}
|
||||
|
||||
|
||||
playAdventurer(&G);
|
||||
|
||||
testing_assert(G.handCount[turn] == starting_hand + 2, 0);
|
||||
testing_assert((G.hand[turn][G.handCount[turn] - 1] >= copper) && (G.hand[turn][G.handCount[turn] - 1] <= gold), 0);
|
||||
testing_assert((G.hand[turn][G.handCount[turn] - 2] >= copper) && (G.hand[turn][G.handCount[turn] - 2] <= gold), 0);
|
||||
}
|
||||
|
||||
printf("Run complete!\n");
|
||||
printf("SUCCESSES: %ld\n", sucesses);
|
||||
|
||||
if(failures > 0){
|
||||
printf("Some tests failed!!!\n");
|
||||
printf("FAILURES: %ld\n", failures);
|
||||
}
|
||||
|
||||
return (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
int testing_assert(int expression, int should_print) {
|
||||
if (expression) {
|
||||
if(should_print){
|
||||
printf("TEST SUCCEEDED!\n");
|
||||
}
|
||||
sucesses++;
|
||||
return 1;
|
||||
} else {
|
||||
if(should_print){
|
||||
printf("TEST FAILED!\n");
|
||||
}
|
||||
failures++;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include "dominion.h"
|
||||
#include "dominion_helpers.h"
|
||||
#include "rngs.h"
|
||||
|
||||
int testing_assert(int expression, int should_print);
|
||||
|
||||
long sucesses = 0;
|
||||
long failures = 0;
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
// Get seed from command line arg and setup randomization or exit
|
||||
if(argc < 2){
|
||||
printf("Please enter a seed value for randomization.\n");
|
||||
printf("usage: %s [seed]\n", argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
long seed = atoi(argv[1]);
|
||||
|
||||
SelectStream(1);
|
||||
PutSeed(seed);
|
||||
|
||||
// Game variables
|
||||
struct gameState G;
|
||||
int k[10] = {adventurer, gardens, embargo, village, minion, mine, cutpurse,
|
||||
sea_hag, tribute, smithy};
|
||||
|
||||
// Initialize the game
|
||||
initializeGame(4, k, seed, &G);
|
||||
|
||||
// Limiting variables
|
||||
unsigned int arbritray_num_tests = 1000000;
|
||||
unsigned int arbitrary_hand_count_max = MAX_HAND - 2;
|
||||
|
||||
for(int z = 0 ; z < arbritray_num_tests ; z++){
|
||||
int turn = floor(Random() * MAX_PLAYERS);
|
||||
int starting_hand = floor(Random() * arbitrary_hand_count_max);
|
||||
|
||||
G.handCount[turn] = starting_hand;
|
||||
G.whoseTurn = turn;
|
||||
|
||||
int outpost_before = G.outpostPlayed;
|
||||
int handcount_before = G.handCount[turn];
|
||||
playOutpost(&G, turn);
|
||||
|
||||
testing_assert(G.outpostPlayed == outpost_before + 1, 0);
|
||||
testing_assert(G.handCount[turn] == handcount_before - 1, 0);
|
||||
}
|
||||
|
||||
printf("Run complete!\n");
|
||||
printf("SUCCESSES: %ld\n", sucesses);
|
||||
|
||||
if(failures > 0){
|
||||
printf("Some tests failed!!!\n");
|
||||
printf("FAILURES: %ld\n", failures);
|
||||
}
|
||||
|
||||
return (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
int testing_assert(int expression, int should_print) {
|
||||
if (expression) {
|
||||
if(should_print){
|
||||
printf("TEST SUCCEEDED!\n");
|
||||
}
|
||||
sucesses++;
|
||||
return 1;
|
||||
} else {
|
||||
if(should_print){
|
||||
printf("TEST FAILED!\n");
|
||||
}
|
||||
failures++;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include "dominion.h"
|
||||
#include "dominion_helpers.h"
|
||||
#include "rngs.h"
|
||||
|
||||
int testing_assert(int expression, int should_print);
|
||||
|
||||
long sucesses = 0;
|
||||
long failures = 0;
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
// Get seed from command line arg and setup randomization or exit
|
||||
if(argc < 2){
|
||||
printf("Please enter a seed value for randomization.\n");
|
||||
printf("usage: %s [seed]\n", argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
long seed = atoi(argv[1]);
|
||||
|
||||
SelectStream(1);
|
||||
PutSeed(seed);
|
||||
|
||||
// Game variables
|
||||
struct gameState G;
|
||||
int k[10] = {adventurer, gardens, embargo, village, minion, mine, cutpurse,
|
||||
sea_hag, tribute, smithy};
|
||||
|
||||
// Initialize the game
|
||||
initializeGame(4, k, seed, &G);
|
||||
|
||||
// Limiting variables
|
||||
unsigned int arbritray_num_tests = 1000000;
|
||||
unsigned int arbitrary_hand_count_max = MAX_HAND - 2;
|
||||
|
||||
for(int z = 0 ; z < arbritray_num_tests ; z++){
|
||||
int turn = floor(Random() * MAX_PLAYERS);
|
||||
int hand_pos = floor(Random() * arbitrary_hand_count_max);
|
||||
|
||||
G.deckCount[turn] = MAX_DECK;
|
||||
G.whoseTurn = turn;
|
||||
|
||||
int hand_count = G.handCount[turn];
|
||||
int num_actions = G.numActions;
|
||||
|
||||
playGreat_Hall(&G, hand_pos);
|
||||
testing_assert(G.handCount[turn] == hand_count, 0);
|
||||
testing_assert(G.numActions == num_actions + 1, 0);
|
||||
|
||||
for(int k = 0 ; k < G.handCount[turn] ; k++){
|
||||
testing_assert((G.hand[turn][k] >= curse) && (G.hand[turn][k] <= treasure_map), 0);
|
||||
}
|
||||
}
|
||||
|
||||
printf("Run complete!\n");
|
||||
printf("SUCCESSES: %ld\n", sucesses);
|
||||
|
||||
if(failures > 0){
|
||||
printf("Some tests failed!!!\n");
|
||||
printf("FAILURES: %ld\n", failures);
|
||||
}
|
||||
|
||||
return (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
int testing_assert(int expression, int should_print) {
|
||||
if (expression) {
|
||||
if(should_print){
|
||||
printf("TEST SUCCEEDED!\n");
|
||||
}
|
||||
sucesses++;
|
||||
return 1;
|
||||
} else {
|
||||
if(should_print){
|
||||
printf("TEST FAILED!\n");
|
||||
}
|
||||
failures++;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
/* -------------------------------------------------------------------------
|
||||
* This is an ANSI C library for multi-stream random number generation.
|
||||
* The use of this library is recommended as a replacement for the ANSI C
|
||||
* rand() and srand() functions, particularly in simulation applications
|
||||
* where the statistical 'goodness' of the random number generator is
|
||||
* important. The library supplies 256 streams of random numbers; use
|
||||
* SelectStream(s) to switch between streams indexed s = 0,1,...,255.
|
||||
*
|
||||
* The streams must be initialized. The recommended way to do this is by
|
||||
* using the function PlantSeeds(x) with the value of x used to initialize
|
||||
* the default stream and all other streams initialized automatically with
|
||||
* values dependent on the value of x. The following convention is used
|
||||
* to initialize the default stream:
|
||||
* if x > 0 then x is the state
|
||||
* if x < 0 then the state is obtained from the system clock
|
||||
* if x = 0 then the state is to be supplied interactively.
|
||||
*
|
||||
* The generator used in this library is a so-called 'Lehmer random number
|
||||
* generator' which returns a pseudo-random number uniformly distributed
|
||||
* 0.0 and 1.0. The period is (m - 1) where m = 2,147,483,647 and the
|
||||
* smallest and largest possible values are (1 / m) and 1 - (1 / m)
|
||||
* respectively. For more details see:
|
||||
*
|
||||
* "Random Number Generators: Good Ones Are Hard To Find"
|
||||
* Steve Park and Keith Miller
|
||||
* Communications of the ACM, October 1988
|
||||
*
|
||||
* Name : rngs.c (Random Number Generation - Multiple Streams)
|
||||
* Authors : Steve Park & Dave Geyer
|
||||
* Language : ANSI C
|
||||
* Latest Revision : 09-22-98
|
||||
* -------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include "rngs.h"
|
||||
|
||||
#define MODULUS 2147483647 /* DON'T CHANGE THIS VALUE */
|
||||
#define MULTIPLIER 48271 /* DON'T CHANGE THIS VALUE */
|
||||
#define CHECK 399268537 /* DON'T CHANGE THIS VALUE */
|
||||
#define STREAMS 256 /* # of streams, DON'T CHANGE THIS VALUE */
|
||||
#define A256 22925 /* jump multiplier, DON'T CHANGE THIS VALUE */
|
||||
#define DEFAULT 123456789 /* initial seed, use 0 < DEFAULT < MODULUS */
|
||||
|
||||
static long seed[STREAMS] = {DEFAULT}; /* current state of each stream */
|
||||
static int stream = 0; /* stream index, 0 is the default */
|
||||
static int initialized = 0; /* test for stream initialization */
|
||||
|
||||
|
||||
double Random(void)
|
||||
/* ----------------------------------------------------------------
|
||||
* Random returns a pseudo-random real number uniformly distributed
|
||||
* between 0.0 and 1.0.
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
const long Q = MODULUS / MULTIPLIER;
|
||||
const long R = MODULUS % MULTIPLIER;
|
||||
long t;
|
||||
|
||||
t = MULTIPLIER * (seed[stream] % Q) - R * (seed[stream] / Q);
|
||||
if (t > 0)
|
||||
seed[stream] = t;
|
||||
else
|
||||
seed[stream] = t + MODULUS;
|
||||
return ((double) seed[stream] / MODULUS);
|
||||
}
|
||||
|
||||
|
||||
void PlantSeeds(long x)
|
||||
/* ---------------------------------------------------------------------
|
||||
* Use this function to set the state of all the random number generator
|
||||
* streams by "planting" a sequence of states (seeds), one per stream,
|
||||
* with all states dictated by the state of the default stream.
|
||||
* The sequence of planted states is separated one from the next by
|
||||
* 8,367,782 calls to Random().
|
||||
* ---------------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
const long Q = MODULUS / A256;
|
||||
const long R = MODULUS % A256;
|
||||
int j;
|
||||
int s;
|
||||
|
||||
initialized = 1;
|
||||
s = stream; /* remember the current stream */
|
||||
SelectStream(0); /* change to stream 0 */
|
||||
PutSeed(x); /* set seed[0] */
|
||||
stream = s; /* reset the current stream */
|
||||
for (j = 1; j < STREAMS; j++) {
|
||||
x = A256 * (seed[j - 1] % Q) - R * (seed[j - 1] / Q);
|
||||
if (x > 0)
|
||||
seed[j] = x;
|
||||
else
|
||||
seed[j] = x + MODULUS;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PutSeed(long x)
|
||||
/* ---------------------------------------------------------------
|
||||
* Use this function to set the state of the current random number
|
||||
* generator stream according to the following conventions:
|
||||
* if x > 0 then x is the state (unless too large)
|
||||
* if x < 0 then the state is obtained from the system clock
|
||||
* if x = 0 then the state is to be supplied interactively
|
||||
* ---------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
char ok = 0;
|
||||
|
||||
if (x > 0)
|
||||
x = x % MODULUS; /* correct if x is too large */
|
||||
if (x < 0)
|
||||
x = ((unsigned long) time((time_t *) NULL)) % MODULUS;
|
||||
if (x == 0)
|
||||
while (!ok) {
|
||||
printf("\nEnter a positive integer seed (9 digits or less) >> ");
|
||||
scanf("%ld", &x);
|
||||
ok = (0 < x) && (x < MODULUS);
|
||||
if (!ok)
|
||||
printf("\nInput out of range ... try again\n");
|
||||
}
|
||||
seed[stream] = x;
|
||||
}
|
||||
|
||||
|
||||
void GetSeed(long *x)
|
||||
/* ---------------------------------------------------------------
|
||||
* Use this function to get the state of the current random number
|
||||
* generator stream.
|
||||
* ---------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
*x = seed[stream];
|
||||
}
|
||||
|
||||
|
||||
void SelectStream(int index)
|
||||
/* ------------------------------------------------------------------
|
||||
* Use this function to set the current random number generator
|
||||
* stream -- that stream from which the next random number will come.
|
||||
* ------------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
stream = ((unsigned int) index) % STREAMS;
|
||||
if ((initialized == 0) && (stream != 0)) /* protect against */
|
||||
PlantSeeds(DEFAULT); /* un-initialized streams */
|
||||
}
|
||||
|
||||
|
||||
void TestRandom(void)
|
||||
/* ------------------------------------------------------------------
|
||||
* Use this (optional) function to test for a correct implementation.
|
||||
* ------------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
long i;
|
||||
long x;
|
||||
/*double u;*/ /* used to be uncommented */
|
||||
char ok = 0;
|
||||
|
||||
SelectStream(0); /* select the default stream */
|
||||
PutSeed(1); /* and set the state to 1 */
|
||||
for(i = 0; i < 10000; i++)
|
||||
Random(); /* used to have u = Random() */
|
||||
GetSeed(&x); /* get the new state value */
|
||||
ok = (x == CHECK); /* and check for correctness */
|
||||
|
||||
SelectStream(1); /* select stream 1 */
|
||||
PlantSeeds(1); /* set the state of all streams */
|
||||
GetSeed(&x); /* get the state of stream 1 */
|
||||
ok = ok && (x == A256); /* x should be the jump multiplier */
|
||||
if (ok)
|
||||
printf("\n The implementation of rngs.c is correct.\n\n");
|
||||
else
|
||||
printf("\n\a ERROR -- the implementation of rngs.c is not correct.\n\n");
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
* Name : rngs.h (header file for the library file rngs.c)
|
||||
* Author : Steve Park & Dave Geyer
|
||||
* Language : ANSI C
|
||||
* Latest Revision : 09-22-98
|
||||
* -----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#if !defined( _RNGS_ )
|
||||
#define _RNGS_
|
||||
|
||||
double Random(void);
|
||||
void PlantSeeds(long x);
|
||||
void GetSeed(long *x);
|
||||
void PutSeed(long x);
|
||||
void SelectStream(int index);
|
||||
void TestRandom(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,27 @@
|
||||
#include "rngs.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc < 3) {
|
||||
printf ("Not enough inputs: seed target\n");
|
||||
}
|
||||
|
||||
SelectStream(1);
|
||||
PutSeed((long)atoi(argv[1]));
|
||||
|
||||
int done = 0;
|
||||
int c = 1000000000;
|
||||
|
||||
while (!done) {
|
||||
c = floor(Random() * 1000000000);
|
||||
// if (c % 100000 == 0) {
|
||||
// printf ("c = %d\n", c);
|
||||
// }
|
||||
if (c == atoi(argv[2])) {
|
||||
printf ("Found the bug!\n");
|
||||
done = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
#include "dominion.h"
|
||||
#include "dominion_helpers.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include "rngs.h"
|
||||
|
||||
#define DEBUG 0
|
||||
#define NOISY_TEST 1
|
||||
|
||||
int main () {
|
||||
|
||||
int r;
|
||||
|
||||
int k[10] = {adventurer, council_room, feast, gardens, mine,
|
||||
remodel, smithy, village, baron, great_hall};
|
||||
|
||||
struct gameState G;
|
||||
|
||||
r = initializeGame(4, k, 1, &G);
|
||||
|
||||
printf ("initializeGame(4, k, 1, &G) = %d\n", r);
|
||||
assert(r == 0);
|
||||
|
||||
r = supplyCount(adventurer, &G);
|
||||
printf ("supplyCount(adventurer, &G) = %d\n", r);
|
||||
assert(r == 10);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
#include "dominion.h"
|
||||
#include "dominion_helpers.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include "rngs.h"
|
||||
|
||||
#define DEBUG 0
|
||||
#define NOISY_TEST 1
|
||||
|
||||
int checkDrawCard(int p, struct gameState *post) {
|
||||
struct gameState pre;
|
||||
memcpy (&pre, post, sizeof(struct gameState));
|
||||
|
||||
int r;
|
||||
// printf ("drawCard PRE: p %d HC %d DeC %d DiC %d\n",
|
||||
// p, pre.handCount[p], pre.deckCount[p], pre.discardCount[p]);
|
||||
|
||||
r = drawCard (p, post);
|
||||
|
||||
//printf ("drawCard POST: p %d HC %d DeC %d DiC %d\n",
|
||||
// p, post->handCount[p], post->deckCount[p], post->discardCount[p]);
|
||||
|
||||
if (pre.deckCount[p] > 0) {
|
||||
pre.handCount[p]++;
|
||||
pre.hand[p][pre.handCount[p]-1] = pre.deck[p][pre.deckCount[p]-1];
|
||||
pre.deckCount[p]--;
|
||||
} else if (pre.discardCount[p] > 0) {
|
||||
memcpy(pre.deck[p], post->deck[p], sizeof(int) * pre.discardCount[p]);
|
||||
memcpy(pre.discard[p], post->discard[p], sizeof(int)*pre.discardCount[p]);
|
||||
pre.hand[p][post->handCount[p]-1] = post->hand[p][post->handCount[p]-1];
|
||||
pre.handCount[p]++;
|
||||
pre.deckCount[p] = pre.discardCount[p]-1;
|
||||
pre.discardCount[p] = 0;
|
||||
}
|
||||
|
||||
assert (r == 0);
|
||||
|
||||
assert(memcmp(&pre, post, sizeof(struct gameState)) == 0);
|
||||
}
|
||||
|
||||
int main () {
|
||||
|
||||
int i, n, r, p, deckCount, discardCount, handCount;
|
||||
|
||||
int k[10] = {adventurer, council_room, feast, gardens, mine,
|
||||
remodel, smithy, village, baron, great_hall};
|
||||
|
||||
|
||||
struct gameState G;
|
||||
|
||||
printf ("Testing buyCard.\n");
|
||||
|
||||
printf ("RANDOM TESTS.\n");
|
||||
|
||||
SelectStream(2);
|
||||
PutSeed(3);
|
||||
|
||||
for (n = 0; n < 2000; n++) {
|
||||
for (i = 0; i < sizeof(struct gameState); i++) {
|
||||
((char*)&G)[i] = floor(Random() * 256);
|
||||
}
|
||||
p = floor(Random() * 2);
|
||||
G.deckCount[p] = floor(Random() * MAX_DECK);
|
||||
G.discardCount[p] = floor(Random() * MAX_DECK);
|
||||
G.handCount[p] = floor(Random() * MAX_HAND);
|
||||
checkDrawCard(p, &G);
|
||||
}
|
||||
|
||||
printf ("ALL TESTS OK\n");
|
||||
|
||||
exit(0);
|
||||
|
||||
printf ("SIMPLE FIXED TESTS.\n");
|
||||
for (p = 0; p < 2; p++) {
|
||||
for (deckCount = 0; deckCount < 5; deckCount++) {
|
||||
for (discardCount = 0; discardCount < 5; discardCount++) {
|
||||
for (handCount = 0; handCount < 5; handCount++) {
|
||||
memset(&G, 23, sizeof(struct gameState));
|
||||
r = initializeGame(2, k, 1, &G);
|
||||
G.deckCount[p] = deckCount;
|
||||
memset(G.deck[p], 0, sizeof(int) * deckCount);
|
||||
G.discardCount[p] = discardCount;
|
||||
memset(G.discard[p], 0, sizeof(int) * discardCount);
|
||||
G.handCount[p] = handCount;
|
||||
memset(G.hand[p], 0, sizeof(int) * handCount);
|
||||
checkDrawCard(p, &G);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
#include "dominion.h"
|
||||
#include "dominion_helpers.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include "rngs.h"
|
||||
|
||||
#define DEBUG 0
|
||||
#define NOISY_TEST 1
|
||||
|
||||
int checkDrawCard(int p, struct gameState *post) {
|
||||
struct gameState pre;
|
||||
memcpy (&pre, post, sizeof(struct gameState));
|
||||
|
||||
int r;
|
||||
// printf ("drawCard PRE: p %d HC %d DeC %d DiC %d\n",
|
||||
// p, pre.handCount[p], pre.deckCount[p], pre.discardCount[p]);
|
||||
|
||||
r = drawCard (p, post);
|
||||
|
||||
//printf ("drawCard POST: p %d HC %d DeC %d DiC %d\n",
|
||||
// p, post->handCount[p], post->deckCount[p], post->discardCount[p]);
|
||||
|
||||
if (pre.deckCount[p] > 0) {
|
||||
pre.handCount[p]++;
|
||||
pre.hand[p][pre.handCount[p]-1] = pre.deck[p][pre.deckCount[p]-1];
|
||||
pre.deckCount[p]--;
|
||||
} else if (pre.discardCount[p] > 0) {
|
||||
memcpy(pre.deck[p], post->deck[p], sizeof(int) * pre.discardCount[p]);
|
||||
memcpy(pre.discard[p], post->discard[p], sizeof(int)*pre.discardCount[p]);
|
||||
pre.hand[p][post->handCount[p]-1] = post->hand[p][post->handCount[p]-1];
|
||||
pre.handCount[p]++;
|
||||
pre.deckCount[p] = pre.discardCount[p]-1;
|
||||
pre.discardCount[p] = 0;
|
||||
}
|
||||
|
||||
assert (r == 0);
|
||||
|
||||
assert(memcmp(&pre, post, sizeof(struct gameState)) == 0);
|
||||
}
|
||||
|
||||
int main () {
|
||||
|
||||
int i, n, r, p, deckCount, discardCount, handCount;
|
||||
|
||||
int k[10] = {adventurer, council_room, feast, gardens, mine,
|
||||
remodel, smithy, village, baron, great_hall};
|
||||
|
||||
struct gameState G;
|
||||
|
||||
printf ("Testing drawCard.\n");
|
||||
|
||||
printf ("RANDOM TESTS.\n");
|
||||
|
||||
SelectStream(2);
|
||||
PutSeed(3);
|
||||
|
||||
for (n = 0; n < 2000; n++) {
|
||||
for (i = 0; i < sizeof(struct gameState); i++) {
|
||||
((char*)&G)[i] = floor(Random() * 256);
|
||||
}
|
||||
p = floor(Random() * 2);
|
||||
G.deckCount[p] = floor(Random() * MAX_DECK);
|
||||
G.discardCount[p] = floor(Random() * MAX_DECK);
|
||||
G.handCount[p] = floor(Random() * MAX_HAND);
|
||||
checkDrawCard(p, &G);
|
||||
}
|
||||
|
||||
printf ("ALL TESTS OK\n");
|
||||
|
||||
exit(0);
|
||||
|
||||
printf ("SIMPLE FIXED TESTS.\n");
|
||||
for (p = 0; p < 2; p++) {
|
||||
for (deckCount = 0; deckCount < 5; deckCount++) {
|
||||
for (discardCount = 0; discardCount < 5; discardCount++) {
|
||||
for (handCount = 0; handCount < 5; handCount++) {
|
||||
memset(&G, 23, sizeof(struct gameState));
|
||||
r = initializeGame(2, k, 1, &G);
|
||||
G.deckCount[p] = deckCount;
|
||||
memset(G.deck[p], 0, sizeof(int) * deckCount);
|
||||
G.discardCount[p] = discardCount;
|
||||
memset(G.discard[p], 0, sizeof(int) * discardCount);
|
||||
G.handCount[p] = handCount;
|
||||
memset(G.hand[p], 0, sizeof(int) * handCount);
|
||||
checkDrawCard(p, &G);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
#include "dominion.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "rngs.h"
|
||||
|
||||
int main (int argc, char** argv) {
|
||||
|
||||
struct gameState G;
|
||||
|
||||
int i;
|
||||
|
||||
int start = -1;
|
||||
|
||||
int k[10] = {adventurer, gardens, embargo, village, minion, mine, cutpurse,
|
||||
sea_hag, tribute, smithy};
|
||||
|
||||
memset(&G, 'z', sizeof(struct gameState));
|
||||
|
||||
initializeGame(4, k, atoi(argv[1]), &G);
|
||||
|
||||
printf ("Rough guide to locations in structure:\n");
|
||||
printf ("0: numPlayers\n");
|
||||
printf ("%ld: supplyCount[0]\n", ((long)&(G.supplyCount[0]))-((long)&G));
|
||||
printf ("%ld: embargoTokens[0]\n", ((long)&(G.embargoTokens[0]))-((long)&G));
|
||||
printf ("%ld: hand[0][0]\n", ((long)&(G.hand[0][0]))-(long)(&G));
|
||||
printf ("%ld: deck[0][0]\n", ((long)&(G.deck[0][0]))-(long)(&G));
|
||||
printf ("%ld: discard[0][0]\n", ((long)&(G.discard[0][0]))-(long)(&G));
|
||||
printf ("%ld: playerCards[0]\n", ((long)&(G.playedCards[0]))-(long)(&G));
|
||||
|
||||
for (i = 0; i < sizeof(struct gameState); i++) {
|
||||
if (((char*)&G)[i] == 'z') {
|
||||
if (start == -1) {
|
||||
start = i;
|
||||
}
|
||||
} else{
|
||||
if (start != -1) {
|
||||
if (start == (i-1)) {
|
||||
printf ("Byte %d uninitialized.\n", start);
|
||||
} else {
|
||||
printf ("Bytes %d-%d uninitialized.\n", start, i-1);
|
||||
}
|
||||
start = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (start != -1) {
|
||||
if (start == (i-1)) {
|
||||
printf ("Byte %d uninitialized.\n", start);
|
||||
} else {
|
||||
printf ("Bytes %d-%d uninitialized.\n", start, i-1);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
#include "dominion.h"
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
int compare(const int* a, const int* b);
|
||||
|
||||
int main () {
|
||||
struct gameState G;
|
||||
struct gameState G2;
|
||||
|
||||
// Initialize G.
|
||||
|
||||
memcpy (&G2, &G, sizeof(struct gameState));
|
||||
|
||||
int ret = shuffle(0,&G);
|
||||
|
||||
if (G.deckCount[0] > 0) {
|
||||
assert (ret != -1);
|
||||
|
||||
qsort ((void*)(G.deck[0]), G.deckCount[0], sizeof(int), compare);
|
||||
qsort ((void*)(G2.deck[0]), G2.deckCount[0], sizeof(int), compare);
|
||||
} else
|
||||
assert (ret == -1);
|
||||
|
||||
assert(memcmp(&G, &G2, sizeof(struct gameState)) == 0);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
/*
|
||||
* File: unittest1.c
|
||||
* Author: corwinperren
|
||||
*
|
||||
* Created on February 1, 2017, 9:02 PM
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "dominion.h"
|
||||
#include "dominion_helpers.h"
|
||||
#include "rngs.h"
|
||||
|
||||
int testing_assert(int expression);
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
struct gameState G;
|
||||
int k[10] = {adventurer, gardens, embargo, village, minion, mine, cutpurse,
|
||||
sea_hag, tribute, smithy};
|
||||
|
||||
initializeGame(2, k, 65432, &G);
|
||||
|
||||
//If province cards are empty or are least three supply piles are, game end
|
||||
//else game is not over. 1 is game end, 0 is game continues
|
||||
|
||||
unsigned int victory_cards_max = 12;
|
||||
unsigned int num_supply_piles = treasure_map+1;
|
||||
unsigned int max_count_for_any_supply = 60;
|
||||
|
||||
int i;
|
||||
for (i = 0; i < victory_cards_max; i++) {
|
||||
int num_zeroed = 0;
|
||||
|
||||
for (int k = 0; k < num_supply_piles; k++) {
|
||||
G.supplyCount[k] = max_count_for_any_supply;
|
||||
}
|
||||
|
||||
for (; num_zeroed < num_supply_piles; num_zeroed++) {
|
||||
for (int j = 0; j < num_zeroed; j++) {
|
||||
G.supplyCount[j] = 0;
|
||||
}
|
||||
|
||||
G.supplyCount[province] = i;
|
||||
|
||||
if ((G.supplyCount[province] == 0) || (num_zeroed >= 3)) {
|
||||
testing_assert(isGameOver(&G) == 1);
|
||||
} else {
|
||||
testing_assert(isGameOver(&G) == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
return (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
int testing_assert(int expression) {
|
||||
if (expression) {
|
||||
printf("TEST SUCCEEDED!\n");
|
||||
return 1;
|
||||
} else {
|
||||
printf("TEST FAILED!\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
/*
|
||||
* File: unittest1.c
|
||||
* Author: corwinperren
|
||||
*
|
||||
* Created on February 1, 2017, 9:02 PM
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "dominion.h"
|
||||
#include "dominion_helpers.h"
|
||||
#include "rngs.h"
|
||||
|
||||
int testing_assert(int expression);
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
struct gameState G;
|
||||
int k[10] = {adventurer, gardens, embargo, village, minion, mine, cutpurse,
|
||||
sea_hag, tribute, smithy};
|
||||
|
||||
unsigned int min_players = 2;
|
||||
unsigned int max_players = MAX_PLAYERS;
|
||||
unsigned int max_hand = MAX_HAND;
|
||||
unsigned int arbitrary_bonus_max = 1000;
|
||||
unsigned int copper_worth = 1;
|
||||
unsigned int silver_worth = 2;
|
||||
unsigned int gold_worth = 3;
|
||||
|
||||
|
||||
for(int i = min_players ; i <= max_players ; i++){
|
||||
initializeGame(i, k, 65432, &G);
|
||||
|
||||
for(int j = 0 ; j < i ; j++){
|
||||
G.handCount[j] = max_hand;
|
||||
|
||||
for(int k = 0 ; k < max_hand ; k++){
|
||||
G.hand[j][k] = copper;
|
||||
}
|
||||
|
||||
updateCoins(j, &G, 0);
|
||||
testing_assert(G.coins == (max_hand*copper_worth));
|
||||
|
||||
updateCoins(j, &G, arbitrary_bonus_max);
|
||||
testing_assert(G.coins == ((max_hand*copper_worth) + arbitrary_bonus_max));
|
||||
|
||||
|
||||
for(int k = 0 ; k < max_hand ; k++){
|
||||
G.hand[j][k] = silver;
|
||||
}
|
||||
|
||||
updateCoins(j, &G, 0);
|
||||
testing_assert(G.coins == (max_hand*silver_worth));
|
||||
|
||||
updateCoins(j, &G, arbitrary_bonus_max);
|
||||
testing_assert(G.coins == ((max_hand*silver_worth) + arbitrary_bonus_max));
|
||||
|
||||
for(int k = 0 ; k < max_hand ; k++){
|
||||
G.hand[j][k] = gold;
|
||||
}
|
||||
|
||||
updateCoins(j, &G, 0);
|
||||
testing_assert(G.coins == (max_hand*gold_worth));
|
||||
|
||||
updateCoins(j, &G, arbitrary_bonus_max);
|
||||
testing_assert(G.coins == ((max_hand*gold_worth) + arbitrary_bonus_max));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
int testing_assert(int expression) {
|
||||
if (expression) {
|
||||
printf("TEST SUCCEEDED!\n");
|
||||
return 1;
|
||||
} else {
|
||||
printf("TEST FAILED!\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
/*
|
||||
* File: unittest1.c
|
||||
* Author: corwinperren
|
||||
*
|
||||
* Created on February 1, 2017, 9:02 PM
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "dominion.h"
|
||||
#include "dominion_helpers.h"
|
||||
#include "rngs.h"
|
||||
|
||||
int testing_assert(int expression);
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
struct gameState G;
|
||||
int k[10] = {adventurer, gardens, embargo, village, minion, mine, cutpurse,
|
||||
sea_hag, tribute, smithy};
|
||||
|
||||
for(int i = 2 ; i <= MAX_PLAYERS ; i++){
|
||||
initializeGame(i, k, 65432, &G);
|
||||
|
||||
for(int j = 0 ; j < i ; j++){
|
||||
G.whoseTurn = j;
|
||||
testing_assert(whoseTurn(&G) == j);
|
||||
}
|
||||
}
|
||||
|
||||
return (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
int testing_assert(int expression) {
|
||||
if (expression) {
|
||||
printf("TEST SUCCEEDED!\n");
|
||||
return 1;
|
||||
} else {
|
||||
printf("TEST FAILED!\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
/*
|
||||
* File: unittest1.c
|
||||
* Author: corwinperren
|
||||
*
|
||||
* Created on February 1, 2017, 9:02 PM
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "dominion.h"
|
||||
#include "dominion_helpers.h"
|
||||
#include "rngs.h"
|
||||
|
||||
int testing_assert(int expression);
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
struct gameState G;
|
||||
int k[10] = {adventurer, gardens, embargo, village, minion, mine, cutpurse,
|
||||
sea_hag, tribute, smithy};
|
||||
|
||||
initializeGame(4, k, 65432, &G);
|
||||
|
||||
unsigned int num_card_types = 27;
|
||||
|
||||
for(int i = 0 ; i < MAX_PLAYERS ; i++){
|
||||
G.whoseTurn = i;
|
||||
G.handCount[i] = MAX_HAND;
|
||||
|
||||
for(int j = 0 ; j < MAX_HAND ; j++){
|
||||
for(int k = 0 ; k < num_card_types ; k++){
|
||||
G.hand[i][j] = k;
|
||||
testing_assert(handCard(j, &G) == k);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
int testing_assert(int expression) {
|
||||
if (expression) {
|
||||
printf("TEST SUCCEEDED!\n");
|
||||
return 1;
|
||||
} else {
|
||||
printf("TEST FAILED!\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
#############################
|
||||
########## Bug #01 ##########
|
||||
#############################
|
||||
Title: playSmithy Incorrect Card Pickup Count
|
||||
|
||||
Affected Files: dominion.c
|
||||
|
||||
Pertinent Code:
|
||||
dominion.c: Line 717
|
||||
|
||||
Test Environment: Red Hat Linux 4.8.5-4 (Kernel 3.10.0)
|
||||
|
||||
Expected Result:
|
||||
A call to playSmithy should add three cards to the player's hand, then
|
||||
discard the played card. The final result should be a hand with two extra cards
|
||||
in it.
|
||||
|
||||
Actual Result:
|
||||
playSmithy picks up five cards instead of three, then discards a card like
|
||||
normal. The result is a hand with four extra cards instead of two.
|
||||
|
||||
Steps to Reproduce:
|
||||
1. Use the other game functions to set up a normal game state.
|
||||
2. Set a current player.
|
||||
3. Save the handcount for the player in a temp variable.
|
||||
4. Call playSmithy against the selected player.
|
||||
5. Compare the saved handcount to the new handcount to see incorrect number.
|
||||
|
||||
|
||||
#############################
|
||||
########## Bug #02 ##########
|
||||
#############################
|
||||
Title: playAdventurer Incorrect Hand Count When Drawing Non-Treasure Cards
|
||||
|
||||
Affected Files: dominion.c
|
||||
|
||||
Pertinent Code:
|
||||
dominion.c: Line 701
|
||||
|
||||
Test Environment: Red Hat Linux 4.8.5-4 (Kernel 3.10.0)
|
||||
|
||||
Expected Result:
|
||||
In a call to playAdventurer, during the process of "picking up" cards,
|
||||
the temp hand stores a copy of any cards that aren't treasure cards, then
|
||||
removes the just saved "top card". This allows cards to be shuffled back into
|
||||
the game without being lost.
|
||||
|
||||
Actual Result:
|
||||
In a call to playAdventurer, during the process of "picking up" cards,
|
||||
instead of removing the top card, an invalid top card is instead added.
|
||||
Depending on the previous state of the hand, the error may not show itself,
|
||||
for example, if every card picked up were a treasure card. In the case where
|
||||
this bug is hit, invalid cards could be shuffled back into the players hand at
|
||||
a later time, causing major bugs in gameplay.
|
||||
|
||||
Steps to Reproduce:
|
||||
1. Use the other game functions to set up a normal game state.
|
||||
2. Set a current player.
|
||||
4. Call playAdventurer against the selected player.
|
||||
5. Manually inspect the hand of the player and note invalid card indexes.
|
||||
@@ -0,0 +1,27 @@
|
||||
CFLAGS = -Wall -fpic -coverage -lm -std=c99 -ftest-coverage -fprofile-arcs
|
||||
|
||||
all: assignment5
|
||||
|
||||
assignment5:
|
||||
echo "Compiling and running all tests....." > unittestresults.out
|
||||
|
||||
gcc -o cardtest2 cardtest2.c dominion.c rngs.c -g $(CFLAGS)
|
||||
echo "Running Cardtest2...." >> unittestresults.out
|
||||
./cardtest2 >> unittestresults.out
|
||||
gcov dominion.c >> unittestresults.out
|
||||
cat dominion.c.gcov >> unittestresults.out
|
||||
cat dominion.c.gcov >> cardtest2.gcov
|
||||
|
||||
echo "######################################" >> unittestresults.out
|
||||
echo "######################################" >> unittestresults.out
|
||||
|
||||
gcc -o cardtest3 cardtest3.c dominion.c rngs.c -g $(CFLAGS)
|
||||
echo "Running Cardtest3...." >> unittestresults.out
|
||||
./cardtest3 >> unittestresults.out
|
||||
gcov dominion.c >> unittestresults.out
|
||||
cat dominion.c.gcov >> unittestresults.out
|
||||
cat dominion.c.gcov >> cardtest3.gcov
|
||||
|
||||
clean:
|
||||
rm -f *.o playdom.exe playdom test.exe test player player.exe testInit testInit.exe *.gcov *.gcda *.gcno *.so *.out
|
||||
rm -f cardtest2 cardtest3
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
/*
|
||||
* File: unittest1.c
|
||||
* Author: corwinperren
|
||||
*
|
||||
* Created on February 1, 2017, 9:02 PM
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "dominion.h"
|
||||
#include "dominion_helpers.h"
|
||||
#include "rngs.h"
|
||||
|
||||
int testing_assert(int expression, int should_print);
|
||||
|
||||
long sucesses = 0;
|
||||
long failures = 0;
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
struct gameState G, G_copy;
|
||||
int k[10] = {adventurer, gardens, embargo, village, minion, mine, cutpurse,
|
||||
sea_hag, tribute, smithy};
|
||||
|
||||
|
||||
unsigned int arbitrary_hand_count_max = MAX_HAND - 3;
|
||||
|
||||
for(int l = 0 ; l < 4 ; l++){
|
||||
for(int i = 1 ; i < arbitrary_hand_count_max ; i++){
|
||||
initializeGame(4, k, 65432, &G);
|
||||
G.handCount[0] = arbitrary_hand_count_max;
|
||||
G.whoseTurn = l;
|
||||
|
||||
G_copy = G;
|
||||
|
||||
drawCard(0, &G_copy);
|
||||
drawCard(0, &G_copy);
|
||||
drawCard(0, &G_copy);
|
||||
discardCard(i, l, &G_copy, 0);
|
||||
|
||||
playSmithy(&G, i, G.whoseTurn);
|
||||
|
||||
testing_assert(G.handCount[l] == G_copy.handCount[l], 0);
|
||||
|
||||
for(int j = 0 ; j < arbitrary_hand_count_max ; j++){
|
||||
testing_assert((G.hand[l][j] >= curse) && (G.hand[l][j] <= treasure_map), 0);
|
||||
testing_assert((G_copy.hand[l][j] >= curse) && (G_copy.hand[l][j] <= treasure_map), 0);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
printf("Run complete!\n");
|
||||
printf("SUCCESSES: %ld\n", sucesses);
|
||||
|
||||
if(failures > 0){
|
||||
printf("Some tests failed!!!\n");
|
||||
printf("FAILURES: %ld\n", failures);
|
||||
}
|
||||
|
||||
return (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
int testing_assert(int expression, int should_print) {
|
||||
if (expression) {
|
||||
if(should_print){
|
||||
printf("TEST SUCCEEDED!\n");
|
||||
}
|
||||
sucesses++;
|
||||
return 1;
|
||||
} else {
|
||||
if(should_print){
|
||||
printf("TEST FAILED!\n");
|
||||
}
|
||||
failures++;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
/*
|
||||
* File: unittest1.c
|
||||
* Author: corwinperren
|
||||
*
|
||||
* Created on February 1, 2017, 9:02 PM
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "dominion.h"
|
||||
#include "dominion_helpers.h"
|
||||
#include "rngs.h"
|
||||
|
||||
int testing_assert(int expression, int should_print);
|
||||
|
||||
long sucesses = 0;
|
||||
long failures = 0;
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
struct gameState G;
|
||||
int k[10] = {adventurer, gardens, embargo, village, minion, mine, cutpurse,
|
||||
sea_hag, tribute, smithy};
|
||||
|
||||
unsigned int arbitrary_hand_count_max = MAX_HAND - 2;
|
||||
|
||||
for(int l = 0 ; l < 4 ; l++){
|
||||
for(int i = 1 ; i < arbitrary_hand_count_max ; i++){
|
||||
initializeGame(4, k, 65432, &G);
|
||||
G.handCount[l] = arbitrary_hand_count_max;
|
||||
G.whoseTurn = l;
|
||||
|
||||
int temp_hand[MAX_HAND];
|
||||
playAdventurer(0, &G, G.whoseTurn, temp_hand, 0);
|
||||
|
||||
testing_assert(G.handCount[l] == arbitrary_hand_count_max + 2, 0);
|
||||
testing_assert((G.hand[l][G.handCount[l] - 1] >= copper) && (G.hand[l][G.handCount[l] - 1] <= gold), 0);
|
||||
testing_assert((G.hand[l][G.handCount[l] - 2] >= copper) && (G.hand[l][G.handCount[l] - 2] <= gold), 0);
|
||||
|
||||
initializeGame(4, k, 65432, &G);
|
||||
G.handCount[l] = arbitrary_hand_count_max;
|
||||
G.whoseTurn = l;
|
||||
G.deckCount[l] = 0;
|
||||
|
||||
for(int m = 0 ; m < MAX_DECK ; m += 3){
|
||||
G.discard[l][m] = copper;
|
||||
G.discard[l][m + 1] = silver;
|
||||
G.discard[l][m + 2] = gold;
|
||||
G.discardCount[l] += 3;
|
||||
}
|
||||
|
||||
playAdventurer(0, &G, G.whoseTurn, temp_hand, 0);
|
||||
|
||||
testing_assert(G.handCount[l] == arbitrary_hand_count_max + 2, 0);
|
||||
testing_assert((G.hand[l][G.handCount[l] - 1] >= copper) && (G.hand[l][G.handCount[l] - 1] <= gold), 0);
|
||||
testing_assert((G.hand[l][G.handCount[l] - 2] >= copper) && (G.hand[l][G.handCount[l] - 2] <= gold), 0);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
printf("Run complete!\n");
|
||||
printf("SUCCESSES: %ld\n", sucesses);
|
||||
|
||||
if(failures > 0){
|
||||
printf("Some tests failed!!!\n");
|
||||
printf("FAILURES: %ld\n", failures);
|
||||
}
|
||||
|
||||
return (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
int testing_assert(int expression, int should_print) {
|
||||
if (expression) {
|
||||
if(should_print){
|
||||
printf("TEST SUCCEEDED!\n");
|
||||
}
|
||||
sucesses++;
|
||||
return 1;
|
||||
} else {
|
||||
if(should_print){
|
||||
printf("TEST FAILED!\n");
|
||||
}
|
||||
failures++;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,143 @@
|
||||
#ifndef _DOMINION_H
|
||||
#define _DOMINION_H
|
||||
|
||||
// Code from various sources, baseline from Kristen Bartosz
|
||||
|
||||
#define MAX_HAND 500
|
||||
#define MAX_DECK 500
|
||||
|
||||
#define MAX_PLAYERS 4
|
||||
|
||||
#define DEBUG 0
|
||||
|
||||
|
||||
|
||||
/* http://dominion.diehrstraits.com has card texts */
|
||||
/* http://dominion.isotropic.org has other stuff */
|
||||
|
||||
/* hand# means index of a card in current active player's hand */
|
||||
|
||||
enum CARD
|
||||
{curse = 0,
|
||||
estate, //1
|
||||
duchy, //2
|
||||
province, //3
|
||||
|
||||
copper, //4
|
||||
silver, //5
|
||||
gold, //6
|
||||
|
||||
adventurer, //7
|
||||
/* If no/only 1 treasure found, stop when full deck seen */
|
||||
council_room, //8
|
||||
feast, //9 /* choice1 is supply # of card gained) */
|
||||
gardens, //10
|
||||
mine, //11 /* choice1 is hand# of money to trash, choice2 is supply# of
|
||||
//money to put in hand */
|
||||
remodel, //12 /* choice1 is hand# of card to remodel, choice2 is supply# */
|
||||
smithy, //13
|
||||
village, //14
|
||||
|
||||
baron, //15 /* choice1: boolean for discard of estate */
|
||||
/* Discard is always of first (lowest index) estate */
|
||||
great_hall, //16
|
||||
minion, //17 /* choice1: 1 = +2 coin, 2 = redraw */
|
||||
steward, //18 /* choice1: 1 = +2 card, 2 = +2 coin, 3 = trash 2 (choice2,3) */
|
||||
tribute, //19
|
||||
|
||||
ambassador, //20 /* choice1 = hand#, choice2 = number to return to supply */
|
||||
cutpurse, //21
|
||||
embargo, //22 /* choice1 = supply# */
|
||||
outpost, //23
|
||||
salvager, //24 /* choice1 = hand# to trash */
|
||||
sea_hag, //25
|
||||
treasure_map //26
|
||||
};
|
||||
|
||||
struct gameState {
|
||||
int numPlayers; //number of players
|
||||
int supplyCount[treasure_map+1]; //this is the amount of a specific type of card given a specific number.
|
||||
int embargoTokens[treasure_map+1];
|
||||
int outpostPlayed;
|
||||
int outpostTurn;
|
||||
int whoseTurn;
|
||||
int phase;
|
||||
int numActions; /* Starts at 1 each turn */
|
||||
int coins; /* Use as you see fit! */
|
||||
int numBuys; /* Starts at 1 each turn */
|
||||
int hand[MAX_PLAYERS][MAX_HAND];
|
||||
int handCount[MAX_PLAYERS];
|
||||
int deck[MAX_PLAYERS][MAX_DECK];
|
||||
int deckCount[MAX_PLAYERS];
|
||||
int discard[MAX_PLAYERS][MAX_DECK];
|
||||
int discardCount[MAX_PLAYERS];
|
||||
int playedCards[MAX_DECK];
|
||||
int playedCardCount;
|
||||
};
|
||||
|
||||
/* All functions return -1 on failure, and DO NOT CHANGE GAME STATE;
|
||||
unless specified for other return, return 0 on success */
|
||||
|
||||
struct gameState* newGame();
|
||||
|
||||
int* kingdomCards(int k1, int k2, int k3, int k4, int k5, int k6, int k7,
|
||||
int k8, int k9, int k10);
|
||||
|
||||
int initializeGame(int numPlayers, int kingdomCards[10], int randomSeed,
|
||||
struct gameState *state);
|
||||
/* Responsible for initializing all supplies, and shuffling deck and
|
||||
drawing starting hands for all players. Check that 10 cards selected
|
||||
are in fact (different) kingdom cards, and that numPlayers is valid.
|
||||
|
||||
Cards not in game should initialize supply position to -1 */
|
||||
|
||||
int shuffle(int player, struct gameState *state);
|
||||
/* Assumes all cards are now in deck array (or hand/played): discard is
|
||||
empty */
|
||||
|
||||
int playCard(int handPos, int choice1, int choice2, int choice3,
|
||||
struct gameState *state);
|
||||
/* Play card with index handPos from current player's hand */
|
||||
|
||||
int buyCard(int supplyPos, struct gameState *state);
|
||||
/* Buy card with supply index supplyPos */
|
||||
|
||||
int numHandCards(struct gameState *state);
|
||||
/* How many cards current player has in hand */
|
||||
|
||||
int handCard(int handNum, struct gameState *state);
|
||||
/* enum value of indexed card in player's hand */
|
||||
|
||||
int supplyCount(int card, struct gameState *state);
|
||||
/* How many of given card are left in supply */
|
||||
|
||||
int fullDeckCount(int player, int card, struct gameState *state);
|
||||
/* Here deck = hand + discard + deck */
|
||||
|
||||
int whoseTurn(struct gameState *state);
|
||||
|
||||
int endTurn(struct gameState *state);
|
||||
/* Must do phase C and advance to next player; do not advance whose turn
|
||||
if game is over */
|
||||
|
||||
int isGameOver(struct gameState *state);
|
||||
|
||||
int scoreFor(int player, struct gameState *state);
|
||||
/* Negative here does not mean invalid; scores may be negative,
|
||||
-9999 means invalid input */
|
||||
|
||||
int getWinners(int players[MAX_PLAYERS], struct gameState *state);
|
||||
/* Set array position of each player who won (remember ties!) to
|
||||
1, others to 0 */
|
||||
|
||||
/*int playAdventurer(struct gameState *state);
|
||||
int playSmithy(struct gameState *state, int handPos);
|
||||
int playVillage(struct gameState *state, int handPos);
|
||||
int playFeast(struct gameState *state, int choice1);
|
||||
int playCouncil_Room(struct gameState *state, int handPos);*/
|
||||
|
||||
int playAdventurer(int drawntreasure, struct gameState *state, int currentPlayer, int temphand[MAX_HAND], int z);
|
||||
int playSmithy(struct gameState *state, int handPos, int currentPlayer);
|
||||
int playVillage(int currentPlayer, struct gameState *state, int handPos);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,15 @@
|
||||
#ifndef _DOMINION_HELPERS_H
|
||||
#define _DOMINION_HELPERS_H
|
||||
|
||||
#include "dominion.h"
|
||||
|
||||
int drawCard(int player, struct gameState *state);
|
||||
int updateCoins(int player, struct gameState *state, int bonus);
|
||||
int discardCard(int handPos, int currentPlayer, struct gameState *state,
|
||||
int trashFlag);
|
||||
int gainCard(int supplyPos, struct gameState *state, int toFlag, int player);
|
||||
int getCost(int cardNumber);
|
||||
int cardEffect(int card, int choice1, int choice2, int choice3,
|
||||
struct gameState *state, int handPos, int *bonus);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,179 @@
|
||||
/* -------------------------------------------------------------------------
|
||||
* This is an ANSI C library for multi-stream random number generation.
|
||||
* The use of this library is recommended as a replacement for the ANSI C
|
||||
* rand() and srand() functions, particularly in simulation applications
|
||||
* where the statistical 'goodness' of the random number generator is
|
||||
* important. The library supplies 256 streams of random numbers; use
|
||||
* SelectStream(s) to switch between streams indexed s = 0,1,...,255.
|
||||
*
|
||||
* The streams must be initialized. The recommended way to do this is by
|
||||
* using the function PlantSeeds(x) with the value of x used to initialize
|
||||
* the default stream and all other streams initialized automatically with
|
||||
* values dependent on the value of x. The following convention is used
|
||||
* to initialize the default stream:
|
||||
* if x > 0 then x is the state
|
||||
* if x < 0 then the state is obtained from the system clock
|
||||
* if x = 0 then the state is to be supplied interactively.
|
||||
*
|
||||
* The generator used in this library is a so-called 'Lehmer random number
|
||||
* generator' which returns a pseudo-random number uniformly distributed
|
||||
* 0.0 and 1.0. The period is (m - 1) where m = 2,147,483,647 and the
|
||||
* smallest and largest possible values are (1 / m) and 1 - (1 / m)
|
||||
* respectively. For more details see:
|
||||
*
|
||||
* "Random Number Generators: Good Ones Are Hard To Find"
|
||||
* Steve Park and Keith Miller
|
||||
* Communications of the ACM, October 1988
|
||||
*
|
||||
* Name : rngs.c (Random Number Generation - Multiple Streams)
|
||||
* Authors : Steve Park & Dave Geyer
|
||||
* Language : ANSI C
|
||||
* Latest Revision : 09-22-98
|
||||
* -------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include "rngs.h"
|
||||
|
||||
#define MODULUS 2147483647 /* DON'T CHANGE THIS VALUE */
|
||||
#define MULTIPLIER 48271 /* DON'T CHANGE THIS VALUE */
|
||||
#define CHECK 399268537 /* DON'T CHANGE THIS VALUE */
|
||||
#define STREAMS 256 /* # of streams, DON'T CHANGE THIS VALUE */
|
||||
#define A256 22925 /* jump multiplier, DON'T CHANGE THIS VALUE */
|
||||
#define DEFAULT 123456789 /* initial seed, use 0 < DEFAULT < MODULUS */
|
||||
|
||||
static long seed[STREAMS] = {DEFAULT}; /* current state of each stream */
|
||||
static int stream = 0; /* stream index, 0 is the default */
|
||||
static int initialized = 0; /* test for stream initialization */
|
||||
|
||||
|
||||
double Random(void)
|
||||
/* ----------------------------------------------------------------
|
||||
* Random returns a pseudo-random real number uniformly distributed
|
||||
* between 0.0 and 1.0.
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
const long Q = MODULUS / MULTIPLIER;
|
||||
const long R = MODULUS % MULTIPLIER;
|
||||
long t;
|
||||
|
||||
t = MULTIPLIER * (seed[stream] % Q) - R * (seed[stream] / Q);
|
||||
if (t > 0)
|
||||
seed[stream] = t;
|
||||
else
|
||||
seed[stream] = t + MODULUS;
|
||||
return ((double) seed[stream] / MODULUS);
|
||||
}
|
||||
|
||||
|
||||
void PlantSeeds(long x)
|
||||
/* ---------------------------------------------------------------------
|
||||
* Use this function to set the state of all the random number generator
|
||||
* streams by "planting" a sequence of states (seeds), one per stream,
|
||||
* with all states dictated by the state of the default stream.
|
||||
* The sequence of planted states is separated one from the next by
|
||||
* 8,367,782 calls to Random().
|
||||
* ---------------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
const long Q = MODULUS / A256;
|
||||
const long R = MODULUS % A256;
|
||||
int j;
|
||||
int s;
|
||||
|
||||
initialized = 1;
|
||||
s = stream; /* remember the current stream */
|
||||
SelectStream(0); /* change to stream 0 */
|
||||
PutSeed(x); /* set seed[0] */
|
||||
stream = s; /* reset the current stream */
|
||||
for (j = 1; j < STREAMS; j++) {
|
||||
x = A256 * (seed[j - 1] % Q) - R * (seed[j - 1] / Q);
|
||||
if (x > 0)
|
||||
seed[j] = x;
|
||||
else
|
||||
seed[j] = x + MODULUS;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PutSeed(long x)
|
||||
/* ---------------------------------------------------------------
|
||||
* Use this function to set the state of the current random number
|
||||
* generator stream according to the following conventions:
|
||||
* if x > 0 then x is the state (unless too large)
|
||||
* if x < 0 then the state is obtained from the system clock
|
||||
* if x = 0 then the state is to be supplied interactively
|
||||
* ---------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
char ok = 0;
|
||||
|
||||
if (x > 0)
|
||||
x = x % MODULUS; /* correct if x is too large */
|
||||
if (x < 0)
|
||||
x = ((unsigned long) time((time_t *) NULL)) % MODULUS;
|
||||
if (x == 0)
|
||||
while (!ok) {
|
||||
printf("\nEnter a positive integer seed (9 digits or less) >> ");
|
||||
scanf("%ld", &x);
|
||||
ok = (0 < x) && (x < MODULUS);
|
||||
if (!ok)
|
||||
printf("\nInput out of range ... try again\n");
|
||||
}
|
||||
seed[stream] = x;
|
||||
}
|
||||
|
||||
|
||||
void GetSeed(long *x)
|
||||
/* ---------------------------------------------------------------
|
||||
* Use this function to get the state of the current random number
|
||||
* generator stream.
|
||||
* ---------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
*x = seed[stream];
|
||||
}
|
||||
|
||||
|
||||
void SelectStream(int index)
|
||||
/* ------------------------------------------------------------------
|
||||
* Use this function to set the current random number generator
|
||||
* stream -- that stream from which the next random number will come.
|
||||
* ------------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
stream = ((unsigned int) index) % STREAMS;
|
||||
if ((initialized == 0) && (stream != 0)) /* protect against */
|
||||
PlantSeeds(DEFAULT); /* un-initialized streams */
|
||||
}
|
||||
|
||||
|
||||
void TestRandom(void)
|
||||
/* ------------------------------------------------------------------
|
||||
* Use this (optional) function to test for a correct implementation.
|
||||
* ------------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
long i;
|
||||
long x;
|
||||
/*double u;*/ /* used to be uncommented */
|
||||
char ok = 0;
|
||||
|
||||
SelectStream(0); /* select the default stream */
|
||||
PutSeed(1); /* and set the state to 1 */
|
||||
for(i = 0; i < 10000; i++)
|
||||
Random(); /* used to have u = Random() */
|
||||
GetSeed(&x); /* get the new state value */
|
||||
ok = (x == CHECK); /* and check for correctness */
|
||||
|
||||
SelectStream(1); /* select stream 1 */
|
||||
PlantSeeds(1); /* set the state of all streams */
|
||||
GetSeed(&x); /* get the state of stream 1 */
|
||||
ok = ok && (x == A256); /* x should be the jump multiplier */
|
||||
if (ok)
|
||||
printf("\n The implementation of rngs.c is correct.\n\n");
|
||||
else
|
||||
printf("\n\a ERROR -- the implementation of rngs.c is not correct.\n\n");
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
* Name : rngs.h (header file for the library file rngs.c)
|
||||
* Author : Steve Park & Dave Geyer
|
||||
* Language : ANSI C
|
||||
* Latest Revision : 09-22-98
|
||||
* -----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#if !defined( _RNGS_ )
|
||||
#define _RNGS_
|
||||
|
||||
double Random(void);
|
||||
void PlantSeeds(long x);
|
||||
void GetSeed(long *x);
|
||||
void PutSeed(long x);
|
||||
void SelectStream(int index);
|
||||
void TestRandom(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,7 @@
|
||||
CFLAGS = -Wall -fpic -coverage -lm -std=c99 -ftest-coverage -fprofile-arcs
|
||||
|
||||
all:
|
||||
gcc -o testme -g testme.c $(CFLAGS)
|
||||
|
||||
clean:
|
||||
rm -f testme testmeresults.out
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* My approach to writing the tests such that it found the error randomly, while
|
||||
* still completing in the shortest possible of time. To do this, I made a char
|
||||
* array that contained only the chars that were tested for to maximize
|
||||
* potential for creating valid strings, and for moving through the states.
|
||||
* To come up with a char, I simply used mod against a call to rand such that it
|
||||
* gave me the index for a character from the array I made.
|
||||
*
|
||||
* For creating valid strings, I allocated memory for the five character string
|
||||
* that would hopefully eventually become the word "reset" and added and extra
|
||||
* spot for the null character. I then called my completed inputChar to get a
|
||||
* random char and place it in each of the five spots in the array. Finally, I
|
||||
* add in the null terminating character.
|
||||
*
|
||||
* In practice, running this does exactly what I want. Due to traversal of
|
||||
* states being a simple matter of getting the right characters, the program's
|
||||
* state moves to nine incredibly fast. Then, all that's left is to iterate over
|
||||
* the random possibilities for strings until it comes up with the word "reset",
|
||||
* at which point the program prints "error" and exits.
|
||||
*/
|
||||
@@ -0,0 +1,84 @@
|
||||
#include<stdio.h>
|
||||
#include<string.h>
|
||||
#include<stdlib.h>
|
||||
#include<time.h>
|
||||
|
||||
#define NUM_VALID_CHARS 13
|
||||
#define STRING_LENGTH 5
|
||||
|
||||
char valid_chars[NUM_VALID_CHARS] = {
|
||||
'(',
|
||||
'[',
|
||||
'{',
|
||||
')',
|
||||
']',
|
||||
'}',
|
||||
' ',
|
||||
'a',
|
||||
'x',
|
||||
'r',
|
||||
'e',
|
||||
's',
|
||||
't'
|
||||
};
|
||||
|
||||
char inputChar()
|
||||
{
|
||||
return valid_chars[rand() % NUM_VALID_CHARS];
|
||||
}
|
||||
|
||||
char *inputString()
|
||||
{
|
||||
char *temp_string = malloc((STRING_LENGTH + 1) * sizeof(char));
|
||||
|
||||
for(int i = 0 ; i < STRING_LENGTH ; i++){
|
||||
temp_string[i] = inputChar();
|
||||
}
|
||||
|
||||
temp_string[STRING_LENGTH] = '\0';
|
||||
|
||||
return temp_string;
|
||||
}
|
||||
|
||||
void testme()
|
||||
{
|
||||
int tcCount = 0;
|
||||
char *s;
|
||||
char c;
|
||||
int state = 0;
|
||||
while (1)
|
||||
{
|
||||
tcCount++;
|
||||
c = inputChar();
|
||||
s = inputString();
|
||||
printf("Iteration %d: c = %c, s = %s, state = %d\n", tcCount, c, s, state);
|
||||
|
||||
if (c == '[' && state == 0) state = 1;
|
||||
if (c == '(' && state == 1) state = 2;
|
||||
if (c == '{' && state == 2) state = 3;
|
||||
if (c == ' '&& state == 3) state = 4;
|
||||
if (c == 'a' && state == 4) state = 5;
|
||||
if (c == 'x' && state == 5) state = 6;
|
||||
if (c == '}' && state == 6) state = 7;
|
||||
if (c == ')' && state == 7) state = 8;
|
||||
if (c == ']' && state == 8) state = 9;
|
||||
if (s[0] == 'r' && s[1] == 'e'
|
||||
&& s[2] == 's' && s[3] == 'e'
|
||||
&& s[4] == 't' && s[5] == '\0'
|
||||
&& state == 9)
|
||||
{
|
||||
printf("error ");
|
||||
free(s);
|
||||
exit(200);
|
||||
}
|
||||
free(s);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
srand(time(NULL));
|
||||
testme();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<component inherit-compiler-output="true" inheritJdk="true">
|
||||
<output-test url="file://$MODULE_DIR$/out/test/URLValidator"/>
|
||||
<exclude-output/>
|
||||
<contentEntry url="file://$MODULE_DIR$"/>
|
||||
</component>
|
||||
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module classpath="eclipse" classpath-dir="$MODULE_DIR$" type="JAVA_MODULE" version="4" />
|
||||
@@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<eclipse-userlibraries />
|
||||
|
||||
@@ -0,0 +1,370 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p><b>Domain name</b> validation routines.</p>
|
||||
*
|
||||
* <p>
|
||||
* This validator provides methods for validating Internet domain names
|
||||
* and top-level domains.
|
||||
* </p>
|
||||
*
|
||||
* <p>Domain names are evaluated according
|
||||
* to the standards <a href="http://www.ietf.org/rfc/rfc1034.txt">RFC1034</a>,
|
||||
* section 3, and <a href="http://www.ietf.org/rfc/rfc1123.txt">RFC1123</a>,
|
||||
* section 2.1. No accomodation is provided for the specialized needs of
|
||||
* other applications; if the domain name has been URL-encoded, for example,
|
||||
* validation will fail even though the equivalent plaintext version of the
|
||||
* same name would have passed.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Validation is also provided for top-level domains (TLDs) as defined and
|
||||
* maintained by the Internet Assigned Numbers Authority (IANA):
|
||||
* </p>
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link #isValidInfrastructureTld} - validates infrastructure TLDs
|
||||
* (<code>.arpa</code>, etc.)</li>
|
||||
* <li>{@link #isValidGenericTld} - validates generic TLDs
|
||||
* (<code>.com, .org</code>, etc.)</li>
|
||||
* <li>{@link #isValidCountryCodeTld} - validates country code TLDs
|
||||
* (<code>.us, .uk, .cn</code>, etc.)</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
* (<b>NOTE</b>: This class does not provide IP address lookup for domain names or
|
||||
* methods to ensure that a given domain name matches a specific IP; see
|
||||
* {@link java.net.InetAddress} for that functionality.)
|
||||
* </p>
|
||||
*
|
||||
* @version $Revision: 1227719 $ $Date: 2012-01-05 09:45:51 -0800 (Thu, 05 Jan 2012) $
|
||||
* @since Validator 1.4
|
||||
*/
|
||||
public class DomainValidator implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -4407125112880174009L;
|
||||
|
||||
// Regular expression strings for hostnames (derived from RFC2396 and RFC 1123)
|
||||
private static final String DOMAIN_LABEL_REGEX = "\\p{Alnum}(?>[\\p{Alnum}-]*\\p{Alnum})*";
|
||||
private static final String TOP_LABEL_REGEX = "\\p{Alpha}{2,}";
|
||||
//christia : bug introduced by arpit
|
||||
//private static final String TOP_LABEL_REGEX = "\\p{A-Z}{2,}";
|
||||
private static final String DOMAIN_NAME_REGEX =
|
||||
"^(?:" + DOMAIN_LABEL_REGEX + "\\.)+" + "(" + TOP_LABEL_REGEX + ")$";
|
||||
|
||||
private final boolean allowLocal;
|
||||
|
||||
/**
|
||||
* Singleton instance of this validator, which
|
||||
* doesn't consider local addresses as valid.
|
||||
*/
|
||||
private static final DomainValidator DOMAIN_VALIDATOR = new DomainValidator(false);
|
||||
|
||||
/**
|
||||
* Singleton instance of this validator, which does
|
||||
* consider local addresses valid.
|
||||
*/
|
||||
private static final DomainValidator DOMAIN_VALIDATOR_WITH_LOCAL = new DomainValidator(true);
|
||||
|
||||
/**
|
||||
* RegexValidator for matching domains.
|
||||
*/
|
||||
private final RegexValidator domainRegex =
|
||||
new RegexValidator(DOMAIN_NAME_REGEX);
|
||||
/**
|
||||
* RegexValidator for matching the a local hostname
|
||||
*/
|
||||
private final RegexValidator hostnameRegex =
|
||||
new RegexValidator(DOMAIN_LABEL_REGEX);
|
||||
|
||||
/**
|
||||
* Returns the singleton instance of this validator. It
|
||||
* will not consider local addresses as valid.
|
||||
* @return the singleton instance of this validator
|
||||
*/
|
||||
public static DomainValidator getInstance() {
|
||||
return DOMAIN_VALIDATOR;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the singleton instance of this validator,
|
||||
* with local validation as required.
|
||||
* @param allowLocal Should local addresses be considered valid?
|
||||
* @return the singleton instance of this validator
|
||||
*/
|
||||
public static DomainValidator getInstance(boolean allowLocal) {
|
||||
if(allowLocal) {
|
||||
return DOMAIN_VALIDATOR_WITH_LOCAL;
|
||||
}
|
||||
return DOMAIN_VALIDATOR;
|
||||
}
|
||||
|
||||
/** Private constructor. */
|
||||
private DomainValidator(boolean allowLocal) {
|
||||
this.allowLocal = allowLocal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the specified <code>String</code> parses
|
||||
* as a valid domain name with a recognized top-level domain.
|
||||
* The parsing is case-sensitive.
|
||||
* @param domain the parameter to check for domain name syntax
|
||||
* @return true if the parameter is a valid domain name
|
||||
*/
|
||||
public boolean isValid(String domain) {
|
||||
String[] groups = domainRegex.match(domain);
|
||||
if (groups != null && groups.length > 0) {
|
||||
return isValidTld(groups[0]);
|
||||
} else if(allowLocal) {
|
||||
if (!hostnameRegex.isValid(domain)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the specified <code>String</code> matches any
|
||||
* IANA-defined top-level domain. Leading dots are ignored if present.
|
||||
* The search is case-sensitive.
|
||||
* @param tld the parameter to check for TLD status
|
||||
* @return true if the parameter is a TLD
|
||||
*/
|
||||
public boolean isValidTld(String tld) {
|
||||
if(allowLocal && isValidLocalTld(tld)) {
|
||||
return true;
|
||||
}
|
||||
return isValidInfrastructureTld(tld)
|
||||
|| isValidGenericTld(tld)
|
||||
|| isValidCountryCodeTld(tld);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the specified <code>String</code> matches any
|
||||
* IANA-defined infrastructure top-level domain. Leading dots are
|
||||
* ignored if present. The search is case-sensitive.
|
||||
* @param iTld the parameter to check for infrastructure TLD status
|
||||
* @return true if the parameter is an infrastructure TLD
|
||||
*/
|
||||
public boolean isValidInfrastructureTld(String iTld) {
|
||||
return INFRASTRUCTURE_TLD_LIST.contains(chompLeadingDot(iTld.toLowerCase()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the specified <code>String</code> matches any
|
||||
* IANA-defined generic top-level domain. Leading dots are ignored
|
||||
* if present. The search is case-sensitive.
|
||||
* @param gTld the parameter to check for generic TLD status
|
||||
* @return true if the parameter is a generic TLD
|
||||
*/
|
||||
public boolean isValidGenericTld(String gTld) {
|
||||
return GENERIC_TLD_LIST.contains(chompLeadingDot(gTld.toLowerCase()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the specified <code>String</code> matches any
|
||||
* IANA-defined country code top-level domain. Leading dots are
|
||||
* ignored if present. The search is case-sensitive.
|
||||
* @param ccTld the parameter to check for country code TLD status
|
||||
* @return true if the parameter is a country code TLD
|
||||
*/
|
||||
public boolean isValidCountryCodeTld(String ccTld) {
|
||||
return COUNTRY_CODE_TLD_LIST.contains(chompLeadingDot(ccTld.toLowerCase()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the specified <code>String</code> matches any
|
||||
* widely used "local" domains (localhost or localdomain). Leading dots are
|
||||
* ignored if present. The search is case-sensitive.
|
||||
* @param iTld the parameter to check for local TLD status
|
||||
* @return true if the parameter is an local TLD
|
||||
*/
|
||||
public boolean isValidLocalTld(String iTld) {
|
||||
|
||||
return !LOCAL_TLD_LIST.contains(chompLeadingDot(iTld.toLowerCase()));
|
||||
}
|
||||
|
||||
private String chompLeadingDot(String str) {
|
||||
if (str.startsWith(".")) {
|
||||
return str.substring(1);
|
||||
} else {
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------
|
||||
// ----- TLDs defined by IANA
|
||||
// ----- Authoritative and comprehensive list at:
|
||||
// ----- http://data.iana.org/TLD/tlds-alpha-by-domain.txt
|
||||
|
||||
private static final String[] INFRASTRUCTURE_TLDS = new String[] {
|
||||
"arpa", // internet infrastructure
|
||||
"root" // diagnostic marker for non-truncated root zone
|
||||
};
|
||||
|
||||
private static final String[] GENERIC_TLDS = new String[] {
|
||||
"aero", // air transport industry
|
||||
"asia", // Pan-Asia/Asia Pacific
|
||||
"biz", // businesses
|
||||
"cat", // Catalan linguistic/cultural community
|
||||
"com", // commercial enterprises
|
||||
"coop", // cooperative associations
|
||||
"info", // informational sites
|
||||
"jobs", // Human Resource managers
|
||||
"mobi", // mobile products and services
|
||||
"museum", // museums, surprisingly enough
|
||||
"name", // individuals' sites
|
||||
"net", // internet support infrastructure/business
|
||||
"org", // noncommercial organizations
|
||||
"pro", // credentialed professionals and entities
|
||||
"tel", // contact data for businesses and individuals
|
||||
"travel", // entities in the travel industry
|
||||
"gov", // United States Government
|
||||
"edu", // accredited postsecondary US education entities
|
||||
"mil", // United States Military
|
||||
"int" // organizations established by international treaty
|
||||
};
|
||||
|
||||
private static final String[] COUNTRY_CODE_TLDS = new String[] {
|
||||
"ac", // Ascension Island
|
||||
"ad", // Andorra
|
||||
"ae", // United Arab Emirates
|
||||
"af", // Afghanistan
|
||||
"ag", // Antigua and Barbuda
|
||||
"ai", // Anguilla
|
||||
"al", // Albania
|
||||
"am", // Armenia
|
||||
"an", // Netherlands Antilles
|
||||
"ao", // Angola
|
||||
"aq", // Antarctica
|
||||
"ar", // Argentina
|
||||
"as", // American Samoa
|
||||
"at", // Austria
|
||||
"au", // Australia (includes Ashmore and Cartier Islands and Coral Sea Islands)
|
||||
"aw", // Aruba
|
||||
"ax", // Åland
|
||||
"az", // Azerbaijan
|
||||
"ba", // Bosnia and Herzegovina
|
||||
"bb", // Barbados
|
||||
"bd", // Bangladesh
|
||||
"be", // Belgium
|
||||
"bf", // Burkina Faso
|
||||
"bg", // Bulgaria
|
||||
"bh", // Bahrain
|
||||
"bi", // Burundi
|
||||
"bj", // Benin
|
||||
"bm", // Bermuda
|
||||
"bn", // Brunei Darussalam
|
||||
"bo", // Bolivia
|
||||
"br", // Brazil
|
||||
"bs", // Bahamas
|
||||
"bt", // Bhutan
|
||||
"bv", // Bouvet Island
|
||||
"bw", // Botswana
|
||||
"by", // Belarus
|
||||
"bz", // Belize
|
||||
"ca", // Canada
|
||||
"cc", // Cocos (Keeling) Islands
|
||||
"cd", // Democratic Republic of the Congo (formerly Zaire)
|
||||
"cf", // Central African Republic
|
||||
"cg", // Republic of the Congo
|
||||
"ch", // Switzerland
|
||||
"ci", // Côte d'Ivoire
|
||||
"ck", // Cook Islands
|
||||
"cl", // Chile
|
||||
"cm", // Cameroon
|
||||
"cn", // China, mainland
|
||||
"co", // Colombia
|
||||
"cr", // Costa Rica
|
||||
"cu", // Cuba
|
||||
"cv", // Cape Verde
|
||||
"cx", // Christmas Island
|
||||
"cy", // Cyprus
|
||||
"cz", // Czech Republic
|
||||
"de", // Germany
|
||||
"dj", // Djibouti
|
||||
"dk", // Denmark
|
||||
"dm", // Dominica
|
||||
"do", // Dominican Republic
|
||||
"dz", // Algeria
|
||||
"ec", // Ecuador
|
||||
"ee", // Estonia
|
||||
"eg", // Egypt
|
||||
"er", // Eritrea
|
||||
"es", // Spain
|
||||
"et", // Ethiopia
|
||||
"eu", // European Union
|
||||
"fi", // Finland
|
||||
"fj", // Fiji
|
||||
"fk", // Falkland Islands
|
||||
"fm", // Federated States of Micronesia
|
||||
"fo", // Faroe Islands
|
||||
"fr", // France
|
||||
"ga", // Gabon
|
||||
"gb", // Great Britain (United Kingdom)
|
||||
"gd", // Grenada
|
||||
"ge", // Georgia
|
||||
"gf", // French Guiana
|
||||
"gg", // Guernsey
|
||||
"gh", // Ghana
|
||||
"gi", // Gibraltar
|
||||
"gl", // Greenland
|
||||
"gm", // The Gambia
|
||||
"gn", // Guinea
|
||||
"gp", // Guadeloupe
|
||||
"gq", // Equatorial Guinea
|
||||
"gr", // Greece
|
||||
"gs", // South Georgia and the South Sandwich Islands
|
||||
"gt", // Guatemala
|
||||
"gu", // Guam
|
||||
"gw", // Guinea-Bissau
|
||||
"gy", // Guyana
|
||||
"hk", // Hong Kong
|
||||
"hm", // Heard Island and McDonald Islands
|
||||
"hn", // Honduras
|
||||
"hr", // Croatia (Hrvatska)
|
||||
"ht", // Haiti
|
||||
"hu", // Hungary
|
||||
"id", // Indonesia
|
||||
"ie", // Ireland (Éire)
|
||||
"il", // Israel
|
||||
"im", // Isle of Man
|
||||
"in", // India
|
||||
"io", // British Indian Ocean Territory
|
||||
"iq", // Iraq
|
||||
"ir", // Iran
|
||||
"is", // Iceland
|
||||
"it", // Italy
|
||||
|
||||
};
|
||||
|
||||
private static final String[] LOCAL_TLDS = new String[] {
|
||||
"localhost", // RFC2606 defined
|
||||
"localdomain" // Also widely used as localhost.localdomain
|
||||
};
|
||||
|
||||
private static final List INFRASTRUCTURE_TLD_LIST = Arrays.asList(INFRASTRUCTURE_TLDS);
|
||||
private static final List GENERIC_TLD_LIST = Arrays.asList(GENERIC_TLDS);
|
||||
private static final List COUNTRY_CODE_TLD_LIST = Arrays.asList(COUNTRY_CODE_TLDS);
|
||||
private static final List LOCAL_TLD_LIST = Arrays.asList(LOCAL_TLDS);
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* <p><b>InetAddress</b> validation and conversion routines (<code>java.net.InetAddress</code>).</p>
|
||||
*
|
||||
* <p>This class provides methods to validate a candidate IP address.
|
||||
*
|
||||
* <p>
|
||||
* This class is a Singleton; you can retrieve the instance via the {@link #getInstance()} method.
|
||||
* </p>
|
||||
*
|
||||
* @version $Revision: 1227719 $
|
||||
* @since Validator 1.4
|
||||
*/
|
||||
public class InetAddressValidator implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -919201640201914789L;
|
||||
|
||||
private static final String IPV4_REGEX =
|
||||
"^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$";
|
||||
|
||||
/**
|
||||
* Singleton instance of this class.
|
||||
*/
|
||||
private static final InetAddressValidator VALIDATOR = new InetAddressValidator();
|
||||
|
||||
/** IPv4 RegexValidator */
|
||||
private final RegexValidator ipv4Validator = new RegexValidator(IPV4_REGEX);
|
||||
|
||||
/**
|
||||
* Returns the singleton instance of this validator.
|
||||
* @return the singleton instance of this validator
|
||||
*/
|
||||
public static InetAddressValidator getInstance() {
|
||||
return VALIDATOR;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the specified string is a valid IP address.
|
||||
* @param inetAddress the string to validate
|
||||
* @return true if the string validates as an IP address
|
||||
*/
|
||||
public boolean isValid(String inetAddress) {
|
||||
|
||||
return isValidInet4Address(inetAddress);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates an IPv4 address. Returns true if valid.
|
||||
* @param inet4Address the IPv4 address to validate
|
||||
* @return true if the argument contains a valid IPv4 address
|
||||
*/
|
||||
public boolean isValidInet4Address(String inet4Address) {
|
||||
// verify that address conforms to generic IPv4 format
|
||||
String[] groups = ipv4Validator.match(inet4Address);
|
||||
|
||||
if (groups == null) return false;
|
||||
|
||||
// verify that address subgroups are legal
|
||||
for (int i = 0; i <= 3; i++) {
|
||||
String ipSegment = groups[i];
|
||||
if (ipSegment == null || ipSegment.length() <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int iIpSegment = 0;
|
||||
|
||||
try {
|
||||
iIpSegment = Integer.parseInt(ipSegment);
|
||||
} catch(NumberFormatException e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (iIpSegment > 255) {
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,216 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.Matcher;
|
||||
|
||||
/**
|
||||
* <b>Regular Expression</b> validation (using JDK 1.4+ regex support).
|
||||
* <p>
|
||||
* Construct the validator either for a single regular expression or a set (array) of
|
||||
* regular expressions. By default validation is <i>case sensitive</i> but constructors
|
||||
* are provided to allow <i>case in-sensitive</i> validation. For example to create
|
||||
* a validator which does <i>case in-sensitive</i> validation for a set of regular
|
||||
* expressions:
|
||||
* <pre>
|
||||
* String[] regexs = new String[] {...};
|
||||
* RegexValidator validator = new RegexValidator(regexs, false);
|
||||
* </pre>
|
||||
* <p>
|
||||
* <ul>
|
||||
* <li>Validate <code>true</code> or <code>false</code>:</li>
|
||||
* <ul>
|
||||
* <li><code>boolean valid = validator.isValid(value);</code></li>
|
||||
* </ul>
|
||||
* <li>Validate returning an aggregated String of the matched groups:</li>
|
||||
* <ul>
|
||||
* <li><code>String result = validator.validate(value);</code></li>
|
||||
* </ul>
|
||||
* <li>Validate returning the matched groups:</li>
|
||||
* <ul>
|
||||
* <li><code>String[] result = validator.match(value);</code></li>
|
||||
* </ul>
|
||||
* </ul>
|
||||
* <p>
|
||||
* Cached instances pre-compile and re-use {@link Pattern}(s) - which according
|
||||
* to the {@link Pattern} API are safe to use in a multi-threaded environment.
|
||||
*
|
||||
* @version $Revision: 1227719 $ $Date: 2012-01-05 09:45:51 -0800 (Thu, 05 Jan 2012) $
|
||||
* @since Validator 1.4
|
||||
*/
|
||||
public class RegexValidator implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -8832409930574867162L;
|
||||
|
||||
private final Pattern[] patterns;
|
||||
|
||||
/**
|
||||
* Construct a <i>case sensitive</i> validator for a single
|
||||
* regular expression.
|
||||
*
|
||||
* @param regex The regular expression this validator will
|
||||
* validate against
|
||||
*/
|
||||
public RegexValidator(String regex) {
|
||||
this(regex, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a validator for a single regular expression
|
||||
* with the specified case sensitivity.
|
||||
*
|
||||
* @param regex The regular expression this validator will
|
||||
* validate against
|
||||
* @param caseSensitive when <code>true</code> matching is <i>case
|
||||
* sensitive</i>, otherwise matching is <i>case in-sensitive</i>
|
||||
*/
|
||||
public RegexValidator(String regex, boolean caseSensitive) {
|
||||
this(new String[] {regex}, caseSensitive);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a <i>case sensitive</i> validator that matches any one
|
||||
* of the set of regular expressions.
|
||||
*
|
||||
* @param regexs The set of regular expressions this validator will
|
||||
* validate against
|
||||
*/
|
||||
public RegexValidator(String[] regexs) {
|
||||
this(regexs, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a validator that matches any one of the set of regular
|
||||
* expressions with the specified case sensitivity.
|
||||
*
|
||||
* @param regexs The set of regular expressions this validator will
|
||||
* validate against
|
||||
* @param caseSensitive when <code>true</code> matching is <i>case
|
||||
* sensitive</i>, otherwise matching is <i>case in-sensitive</i>
|
||||
*/
|
||||
public RegexValidator(String[] regexs, boolean caseSensitive) {
|
||||
if (regexs == null || regexs.length == 0) {
|
||||
throw new IllegalArgumentException("Regular expressions are missing");
|
||||
}
|
||||
patterns = new Pattern[regexs.length];
|
||||
int flags = (caseSensitive ? 0: Pattern.CASE_INSENSITIVE);
|
||||
for (int i = 0; i < regexs.length; i++) {
|
||||
if (regexs[i] == null || regexs[i].length() == 0) {
|
||||
throw new IllegalArgumentException("Regular expression[" + i + "] is missing");
|
||||
}
|
||||
patterns[i] = Pattern.compile(regexs[i], flags);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a value against the set of regular expressions.
|
||||
*
|
||||
* @param value The value to validate.
|
||||
* @return <code>true</code> if the value is valid
|
||||
* otherwise <code>false</code>.
|
||||
*/
|
||||
public boolean isValid(String value) {
|
||||
if (value == null) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < patterns.length; i++) {
|
||||
if (patterns[i].matcher(value).matches()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a value against the set of regular expressions
|
||||
* returning the array of matched groups.
|
||||
*
|
||||
* @param value The value to validate.
|
||||
* @return String array of the <i>groups</i> matched if
|
||||
* valid or <code>null</code> if invalid
|
||||
*/
|
||||
public String[] match(String value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
for (int i = 0; i < patterns.length; i++) {
|
||||
Matcher matcher = patterns[i].matcher(value);
|
||||
if (matcher.matches()) {
|
||||
int count = matcher.groupCount();
|
||||
String[] groups = new String[count];
|
||||
for (int j = 0; j < count; j++) {
|
||||
groups[j] = matcher.group(j+1);
|
||||
}
|
||||
return groups;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Validate a value against the set of regular expressions
|
||||
* returning a String value of the aggregated groups.
|
||||
*
|
||||
* @param value The value to validate.
|
||||
* @return Aggregated String value comprised of the
|
||||
* <i>groups</i> matched if valid or <code>null</code> if invalid
|
||||
*/
|
||||
public String validate(String value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
for (int i = 0; i < patterns.length; i++) {
|
||||
Matcher matcher = patterns[i].matcher(value);
|
||||
if (matcher.matches()) {
|
||||
int count = matcher.groupCount();
|
||||
if (count == 1) {
|
||||
return matcher.group(1);
|
||||
}
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
for (int j = 0; j < count; j++) {
|
||||
String component = matcher.group(j+1);
|
||||
if (component != null) {
|
||||
buffer.append(component);
|
||||
}
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a String representation of this validator.
|
||||
* @return A String representation of this validator
|
||||
*/
|
||||
public String toString() {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
buffer.append("RegexValidator{");
|
||||
for (int i = 0; i < patterns.length; i++) {
|
||||
if (i > 0) {
|
||||
buffer.append(",");
|
||||
}
|
||||
buffer.append(patterns[i].pattern());
|
||||
}
|
||||
buffer.append("}");
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Groups tests and expected results.
|
||||
*
|
||||
* @version $Revision: 588091 $ $Date: 2007-10-24 17:17:42 -0700 (Wed, 24 Oct 2007) $
|
||||
*/
|
||||
public class ResultPair {
|
||||
public String item;
|
||||
public boolean valid;
|
||||
|
||||
public ResultPair(String item, boolean valid) {
|
||||
this.item = item;
|
||||
this.valid = valid; //Weather the individual part of url is valid.
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,504 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* <p><b>URL Validation</b> routines.</p>
|
||||
* Behavior of validation is modified by passing in options:
|
||||
* <li>ALLOW_2_SLASHES - [FALSE] Allows double '/' characters in the path
|
||||
* component.</li>
|
||||
* <li>NO_FRAGMENT- [FALSE] By default fragments are allowed, if this option is
|
||||
* included then fragments are flagged as illegal.</li>
|
||||
* <li>ALLOW_ALL_SCHEMES - [FALSE] By default only http, https, and ftp are
|
||||
* considered valid schemes. Enabling this option will let any scheme pass validation.</li>
|
||||
*
|
||||
* <p>Originally based in on php script by Debbie Dyer, validation.php v1.2b, Date: 03/07/02,
|
||||
* http://javascript.internet.com. However, this validation now bears little resemblance
|
||||
* to the php original.</p>
|
||||
* <pre>
|
||||
* Example of usage:
|
||||
* Construct a UrlValidator with valid schemes of "http", and "https".
|
||||
*
|
||||
* String[] schemes = {"http","https"}.
|
||||
* UrlValidator urlValidator = new UrlValidator(schemes);
|
||||
* if (urlValidator.isValid("ftp://foo.bar.com/")) {
|
||||
* System.out.println("url is valid");
|
||||
* } else {
|
||||
* System.out.println("url is invalid");
|
||||
* }
|
||||
*
|
||||
* prints "url is invalid"
|
||||
* If instead the default constructor is used.
|
||||
*
|
||||
* UrlValidator urlValidator = new UrlValidator();
|
||||
* if (urlValidator.isValid("ftp://foo.bar.com/")) {
|
||||
* System.out.println("url is valid");
|
||||
* } else {
|
||||
* System.out.println("url is invalid");
|
||||
* }
|
||||
*
|
||||
* prints out "url is valid"
|
||||
* </pre>
|
||||
*
|
||||
* @see
|
||||
* <a href="http://www.ietf.org/rfc/rfc2396.txt">
|
||||
* Uniform Resource Identifiers (URI): Generic Syntax
|
||||
* </a>
|
||||
*
|
||||
* @version $Revision: 1227719 $ $Date: 2012-01-05 09:45:51 -0800 (Thu, 05 Jan 2012) $
|
||||
* @since Validator 1.4
|
||||
*/
|
||||
public class UrlValidator implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 7557161713937335013L;
|
||||
|
||||
/**
|
||||
* Allows all validly formatted schemes to pass validation instead of
|
||||
* supplying a set of valid schemes.
|
||||
*/
|
||||
public static final long ALLOW_ALL_SCHEMES = 1 << 0;
|
||||
|
||||
/**
|
||||
* Allow two slashes in the path component of the URL.
|
||||
*/
|
||||
public static final long ALLOW_2_SLASHES = 1 << 1;
|
||||
|
||||
/**
|
||||
* Enabling this options disallows any URL fragments.
|
||||
*/
|
||||
public static final long NO_FRAGMENTS = 1 << 2;
|
||||
|
||||
/**
|
||||
* Allow local URLs, such as http://localhost/ or http://machine/ .
|
||||
* This enables a broad-brush check, for complex local machine name
|
||||
* validation requirements you should create your validator with
|
||||
* a {@link RegexValidator} instead ({@link #UrlValidator(RegexValidator, long)})
|
||||
*/
|
||||
public static final long ALLOW_LOCAL_URLS = 1 << 3;
|
||||
|
||||
// Drop numeric, and "+-." for now
|
||||
private static final String AUTHORITY_CHARS_REGEX = "\\p{Alnum}\\-\\.";
|
||||
|
||||
/**
|
||||
* This expression derived/taken from the BNF for URI (RFC2396).
|
||||
*/
|
||||
private static final String URL_REGEX =
|
||||
"^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?";
|
||||
// 12 3 4 5 6 7 8 9
|
||||
private static final Pattern URL_PATTERN = Pattern.compile(URL_REGEX);
|
||||
|
||||
/**
|
||||
* Schema/Protocol (ie. http:, ftp:, file:, etc).
|
||||
*/
|
||||
private static final int PARSE_URL_SCHEME = 2;
|
||||
|
||||
/**
|
||||
* Includes hostname/ip and port number.
|
||||
*/
|
||||
private static final int PARSE_URL_AUTHORITY = 4;
|
||||
|
||||
private static final int PARSE_URL_PATH = 5;
|
||||
|
||||
private static final int PARSE_URL_QUERY = 7;
|
||||
|
||||
private static final int PARSE_URL_FRAGMENT = 9;
|
||||
|
||||
/**
|
||||
* Protocol (ie. http:, ftp:,https:).
|
||||
*/
|
||||
private static final String SCHEME_REGEX = "^\\p{Alpha}[\\p{Alnum}\\+\\-\\.]*";
|
||||
private static final Pattern SCHEME_PATTERN = Pattern.compile(SCHEME_REGEX);
|
||||
|
||||
private static final String AUTHORITY_REGEX =
|
||||
"^([" + AUTHORITY_CHARS_REGEX + "]*)(:\\d*)?(.*)?";
|
||||
// 1 2 3 4
|
||||
private static final Pattern AUTHORITY_PATTERN = Pattern.compile(AUTHORITY_REGEX);
|
||||
|
||||
private static final int PARSE_AUTHORITY_HOST_IP = 1;
|
||||
|
||||
private static final int PARSE_AUTHORITY_PORT = 2;
|
||||
|
||||
/**
|
||||
* Should always be empty.
|
||||
*/
|
||||
private static final int PARSE_AUTHORITY_EXTRA = 3;
|
||||
|
||||
private static final String PATH_REGEX = "^(/[-\\w:@&?=+,.!/~*'%$_;\\(\\)]*)?$";
|
||||
private static final Pattern PATH_PATTERN = Pattern.compile(PATH_REGEX);
|
||||
|
||||
private static final String QUERY_REGEX = "^(.*)$";
|
||||
|
||||
private static final Pattern QUERY_PATTERN = Pattern.compile(QUERY_REGEX);
|
||||
|
||||
private static final String LEGAL_ASCII_REGEX = "^\\p{ASCII}+$";
|
||||
private static final Pattern ASCII_PATTERN = Pattern.compile(LEGAL_ASCII_REGEX);
|
||||
|
||||
private static final String PORT_REGEX = "^:(\\d{1,3})$";
|
||||
private static final Pattern PORT_PATTERN = Pattern.compile(PORT_REGEX);
|
||||
|
||||
/**
|
||||
* Holds the set of current validation options.
|
||||
*/
|
||||
private final long options;
|
||||
|
||||
/**
|
||||
* The set of schemes that are allowed to be in a URL.
|
||||
*/
|
||||
private final Set allowedSchemes;
|
||||
|
||||
/**
|
||||
* Regular expressions used to manually validate authorities if IANA
|
||||
* domain name validation isn't desired.
|
||||
*/
|
||||
private final RegexValidator authorityValidator;
|
||||
|
||||
/**
|
||||
* If no schemes are provided, default to this set.
|
||||
*/
|
||||
private static final String[] DEFAULT_SCHEMES = {"http", "https", "ftp"};
|
||||
|
||||
/**
|
||||
* Singleton instance of this class with default schemes and options.
|
||||
*/
|
||||
private static final UrlValidator DEFAULT_URL_VALIDATOR = new UrlValidator();
|
||||
|
||||
/**
|
||||
* Returns the singleton instance of this class with default schemes and options.
|
||||
* @return singleton instance with default schemes and options
|
||||
*/
|
||||
public static UrlValidator getInstance() {
|
||||
return DEFAULT_URL_VALIDATOR;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a UrlValidator with default properties.
|
||||
*/
|
||||
public UrlValidator() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Behavior of validation is modified by passing in several strings options:
|
||||
* @param schemes Pass in one or more url schemes to consider valid, passing in
|
||||
* a null will default to "http,https,ftp" being valid.
|
||||
* If a non-null schemes is specified then all valid schemes must
|
||||
* be specified. Setting the ALLOW_ALL_SCHEMES option will
|
||||
* ignore the contents of schemes.
|
||||
*/
|
||||
public UrlValidator(String[] schemes) {
|
||||
this(schemes, 0L);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a UrlValidator with the given validation options.
|
||||
* @param options The options should be set using the public constants declared in
|
||||
* this class. To set multiple options you simply add them together. For example,
|
||||
* ALLOW_2_SLASHES + NO_FRAGMENTS enables both of those options.
|
||||
*/
|
||||
public UrlValidator(long options) {
|
||||
this(null, null, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Behavior of validation is modified by passing in options:
|
||||
* @param schemes The set of valid schemes.
|
||||
* @param options The options should be set using the public constants declared in
|
||||
* this class. To set multiple options you simply add them together. For example,
|
||||
* ALLOW_2_SLASHES + NO_FRAGMENTS enables both of those options.
|
||||
*/
|
||||
public UrlValidator(String[] schemes, long options) {
|
||||
this(schemes, null, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a UrlValidator with the given validation options.
|
||||
* @param authorityValidator Regular expression validator used to validate the authority part
|
||||
* @param options Validation options. Set using the public constants of this class.
|
||||
* To set multiple options, simply add them together:
|
||||
* <p><code>ALLOW_2_SLASHES + NO_FRAGMENTS</code></p>
|
||||
* enables both of those options.
|
||||
*/
|
||||
public UrlValidator(RegexValidator authorityValidator, long options) {
|
||||
this(null, authorityValidator, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Customizable constructor. Validation behavior is modifed by passing in options.
|
||||
* @param schemes the set of valid schemes
|
||||
* @param authorityValidator Regular expression validator used to validate the authority part
|
||||
* @param options Validation options. Set using the public constants of this class.
|
||||
* To set multiple options, simply add them together:
|
||||
* <p><code>ALLOW_2_SLASHES + NO_FRAGMENTS</code></p>
|
||||
* enables both of those options.
|
||||
*/
|
||||
public UrlValidator(String[] schemes, RegexValidator authorityValidator, long options) {
|
||||
this.options = options;
|
||||
|
||||
if (isOn(ALLOW_ALL_SCHEMES)) {
|
||||
this.allowedSchemes = Collections.EMPTY_SET;
|
||||
} else {
|
||||
if (schemes == null) {
|
||||
schemes = DEFAULT_SCHEMES;
|
||||
}
|
||||
this.allowedSchemes = new HashSet();
|
||||
this.allowedSchemes.addAll(Arrays.asList(schemes));
|
||||
}
|
||||
|
||||
this.authorityValidator = authorityValidator;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Checks if a field has a valid url address.</p>
|
||||
*
|
||||
* @param value The value validation is being performed on. A <code>null</code>
|
||||
* value is considered invalid.
|
||||
* @return true if the url is valid.
|
||||
*/
|
||||
public boolean isValid(String value) {
|
||||
if (value == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ASCII_PATTERN.matcher(value).matches()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check the whole url address structure
|
||||
Matcher urlMatcher = URL_PATTERN.matcher(value);
|
||||
if (!urlMatcher.matches()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String scheme = urlMatcher.group(PARSE_URL_SCHEME);
|
||||
if (!isValidScheme(scheme)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String authority = urlMatcher.group(PARSE_URL_AUTHORITY);
|
||||
if ("file".equals(scheme) && "".equals(authority)) {
|
||||
// Special case - file: allows an empty authority
|
||||
} else {
|
||||
// Validate the authority
|
||||
if (!isValidAuthority(authority)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isValidPath(urlMatcher.group(PARSE_URL_PATH))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isValidQuery(urlMatcher.group(PARSE_URL_QUERY))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isValidFragment(urlMatcher.group(PARSE_URL_FRAGMENT))) {
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate scheme. If schemes[] was initialized to a non null,
|
||||
* then only those scheme's are allowed. Note this is slightly different
|
||||
* than for the constructor.
|
||||
* @param scheme The scheme to validate. A <code>null</code> value is considered
|
||||
* invalid.
|
||||
* @return true if valid.
|
||||
*/
|
||||
protected boolean isValidScheme(String scheme) {
|
||||
if (scheme == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SCHEME_PATTERN.matcher(scheme).matches()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isOff(ALLOW_ALL_SCHEMES)) {
|
||||
|
||||
if (!this.allowedSchemes.contains(scheme)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the authority is properly formatted. An authority is the combination
|
||||
* of hostname and port. A <code>null</code> authority value is considered invalid.
|
||||
* @param authority Authority value to validate.
|
||||
* @return true if authority (hostname and port) is valid.
|
||||
*/
|
||||
protected boolean isValidAuthority(String authority) {
|
||||
if (authority == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// check manual authority validation if specified
|
||||
if (authorityValidator != null) {
|
||||
if (authorityValidator.isValid(authority)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Matcher authorityMatcher = AUTHORITY_PATTERN.matcher(authority);
|
||||
if (!authorityMatcher.matches()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String hostLocation = authorityMatcher.group(PARSE_AUTHORITY_HOST_IP);
|
||||
// check if authority is hostname or IP address:
|
||||
// try a hostname first since that's much more likely
|
||||
DomainValidator domainValidator = DomainValidator.getInstance(isOn(ALLOW_LOCAL_URLS));
|
||||
if (!domainValidator.isValid(hostLocation)) {
|
||||
// try an IP address
|
||||
InetAddressValidator inetAddressValidator =
|
||||
InetAddressValidator.getInstance();
|
||||
if (!inetAddressValidator.isValid(hostLocation)) {
|
||||
// isn't either one, so the URL is invalid
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
String port = authorityMatcher.group(PARSE_AUTHORITY_PORT);
|
||||
if (port != null) {
|
||||
if (!PORT_PATTERN.matcher(port).matches()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
String extra = authorityMatcher.group(PARSE_AUTHORITY_EXTRA);
|
||||
if (extra != null && extra.trim().length() > 0){
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the path is valid. A <code>null</code> value is considered invalid.
|
||||
* @param path Path value to validate.
|
||||
* @return true if path is valid.
|
||||
*/
|
||||
protected boolean isValidPath(String path) {
|
||||
if (path == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!PATH_PATTERN.matcher(path).matches()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int slash2Count = countToken("//", path);
|
||||
if (isOff(ALLOW_2_SLASHES) && (slash2Count > 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int slashCount = countToken("/", path);
|
||||
int dot2Count = countToken("..", path);
|
||||
if (dot2Count > 0) {
|
||||
if ((slashCount - slash2Count - 1) <= dot2Count) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the query is null or it's a properly formatted query string.
|
||||
* @param query Query value to validate.
|
||||
* @return true if query is valid.
|
||||
*/
|
||||
protected boolean isValidQuery(String query) {
|
||||
if (query == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return !QUERY_PATTERN.matcher(query).matches();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given fragment is null or fragments are allowed.
|
||||
* @param fragment Fragment value to validate.
|
||||
* @return true if fragment is valid.
|
||||
*/
|
||||
protected boolean isValidFragment(String fragment) {
|
||||
if (fragment == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return isOff(NO_FRAGMENTS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of times the token appears in the target.
|
||||
* @param token Token value to be counted.
|
||||
* @param target Target value to count tokens in.
|
||||
* @return the number of tokens.
|
||||
*/
|
||||
protected int countToken(String token, String target) {
|
||||
int tokenIndex = 0;
|
||||
int count = 0;
|
||||
while (tokenIndex != -1) {
|
||||
tokenIndex = target.indexOf(token, tokenIndex);
|
||||
if (tokenIndex > -1) {
|
||||
tokenIndex++;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether the given flag is on. If the flag is not a power of 2
|
||||
* (ie. 3) this tests whether the combination of flags is on.
|
||||
*
|
||||
* @param flag Flag value to check.
|
||||
*
|
||||
* @return whether the specified flag value is on.
|
||||
*/
|
||||
private boolean isOn(long flag) {
|
||||
return (this.options & flag) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether the given flag is off. If the flag is not a power of 2
|
||||
* (ie. 3) this tests whether the combination of flags is off.
|
||||
*
|
||||
* @param flag Flag value to check.
|
||||
*
|
||||
* @return whether the specified flag value is off.
|
||||
*/
|
||||
private boolean isOff(long flag) {
|
||||
return (this.options & flag) == 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,338 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.LineNumberReader;
|
||||
import java.util.Random;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
* Performs Validation Test for url validations.
|
||||
*
|
||||
* @version $Revision: 1128446 $ $Date: 2011-05-27 13:29:27 -0700 (Fri, 27 May
|
||||
* 2011) $
|
||||
*/
|
||||
public class UrlValidatorTest extends TestCase {
|
||||
|
||||
private boolean printStatus = false;
|
||||
private boolean printIndex = false;// print index that indicates current
|
||||
// scheme,host,port,path, query test
|
||||
// were using.
|
||||
|
||||
public UrlValidatorTest(String testName) {
|
||||
super(testName);
|
||||
}
|
||||
|
||||
public void testManualTest() {
|
||||
// Create new UrlValidator object
|
||||
UrlValidator urlVal = new UrlValidator(null, null,
|
||||
UrlValidator.ALLOW_ALL_SCHEMES);
|
||||
|
||||
// Manual Tests:
|
||||
|
||||
// These should return True
|
||||
System.out.println("The following should return true:");
|
||||
System.out.println(urlVal.isValid("http://www.amazon.com"));
|
||||
System.out.println(urlVal.isValid("http://www.google.com"));
|
||||
System.out.println(urlVal.isValid("http://www.com")); // Oddly enough
|
||||
// this is a
|
||||
// legit website
|
||||
System.out.println(urlVal.isValid("http://www.GOOGLE.com"));
|
||||
System.out.println(urlVal.isValid("HTTP://WWW.GOOGLE.COM"));
|
||||
System.out.println(urlVal.isValid("http://WWW.google.COM"));
|
||||
System.out.println(urlVal.isValid("reddit.com")); // RETURNS FALSE
|
||||
|
||||
// These should return False
|
||||
System.out.println("The following should return false:");
|
||||
System.out.println(urlVal.isValid("http://www.invalid"));
|
||||
System.out.println(urlVal.isValid("reddit"));
|
||||
System.out.println(urlVal.isValid("www.reddit"));
|
||||
System.out.println(urlVal.isValid("al;skdjfals;kdjgas"));
|
||||
System.out.println(urlVal.isValid("www.:).com"));
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* The URLValidator can be split up into two disjoint sets of tests, tests
|
||||
* that should pass and tests that should fail. This is consistent with an
|
||||
* explanation of Input Domain Partitioning as found in an article written
|
||||
* by Tomas Vagoun for the Annual Hawaii International Conference on System
|
||||
* Sciences (https://goo.gl/acd0IL).
|
||||
*
|
||||
* This verifies that the basics of the validator do work, and approaching
|
||||
* this problem as black box testing is some of the best that we can do.
|
||||
*/
|
||||
|
||||
public void testYourFirstPartition() {
|
||||
UrlValidator urlVal = new UrlValidator(null, null,
|
||||
UrlValidator.ALLOW_ALL_SCHEMES);
|
||||
|
||||
String test;
|
||||
|
||||
// This extremely ubiquitous URL is obviously completely true, and as
|
||||
// such, the validator should return true.
|
||||
|
||||
test = "http://www.google.com";
|
||||
if (urlVal.isValid(test) == true) {
|
||||
System.out.println("Passed correctly at " + test + ".");
|
||||
} else {
|
||||
System.out.println("Failed incorrectly at " + test + ".");
|
||||
}
|
||||
|
||||
// This test happened to fail, so I wrote my bug report about it
|
||||
test = "http://www.google.xxx";
|
||||
if (urlVal.isValid(test) == true) {
|
||||
System.out.println("Passed correctly at " + test + ".");
|
||||
} else {
|
||||
System.out.println("Failed incorrectly at " + test + ".");
|
||||
}
|
||||
|
||||
// This test happened to fail, so I wrote my bug report about it
|
||||
test = "http://www.peta.xxx";
|
||||
if (urlVal.isValid(test) == true) {
|
||||
System.out.println("Passed correctly at " + test + ".");
|
||||
} else {
|
||||
System.out.println("Failed incorrectly at " + test + ".");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void testYourSecondPartition() {
|
||||
UrlValidator urlVal = new UrlValidator(null, null,
|
||||
UrlValidator.ALLOW_ALL_SCHEMES);
|
||||
|
||||
String test;
|
||||
|
||||
// But we can detect that the isvalid fails on a known incorrect version
|
||||
// so prove that it can still detect invalid URLs.
|
||||
test = "http://www.google.government";
|
||||
if (urlVal.isValid(test) == false) {
|
||||
System.out.println("Failed correctly at " + test + ".");
|
||||
} else {
|
||||
System.out.println("Failed incorrectly at " + test + ".");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void testIsValid() {
|
||||
// Print out that we're starting
|
||||
System.out.println("Starting programmatically generated tests!");
|
||||
|
||||
// Make an instance of the url validator class
|
||||
UrlValidator url_validator = new UrlValidator(null, null,
|
||||
UrlValidator.ALLOW_ALL_SCHEMES);
|
||||
|
||||
// Instantiate the random number generator
|
||||
Random random_generator = new Random();
|
||||
|
||||
// Read in result pair arrays from the files that contain the test input
|
||||
ResultPair[] test_schemes = get_result_pairs_from_file("test_files/test_schemes.txt");
|
||||
ResultPair[] test_authorities = get_result_pairs_from_file("test_files/test_authorities.txt");
|
||||
ResultPair[] test_ports = get_result_pairs_from_file("test_files/test_ports.txt");
|
||||
ResultPair[] test_paths = get_result_pairs_from_file("test_files/test_paths.txt");
|
||||
|
||||
// Set up some variables for keeping track of suceeded/failed tests.
|
||||
int match_count = 0;
|
||||
int fail_count = 0;
|
||||
|
||||
// Main loop that will run the programmatic tests for so many times
|
||||
for (int i = 0; i < 100000; i++) {
|
||||
// Set up variables for another run through the loop
|
||||
String full_url_string = "";
|
||||
Boolean expected_validity = true;
|
||||
int current_rand = -1;
|
||||
|
||||
// Get a random scheme, concatenate its string with the full url,
|
||||
// and bitwise and its validity result so the result becomes false
|
||||
// if necessary
|
||||
current_rand = random_generator.nextInt(test_schemes.length);
|
||||
full_url_string += test_schemes[current_rand].item;
|
||||
expected_validity &= test_schemes[current_rand].valid;
|
||||
|
||||
// Get a random authority, concatenate its string with the full url,
|
||||
// and bitwise and its validity result so the result becomes false
|
||||
// if necessary
|
||||
current_rand = random_generator.nextInt(test_authorities.length);
|
||||
full_url_string += test_authorities[current_rand].item;
|
||||
expected_validity &= test_authorities[current_rand].valid;
|
||||
|
||||
// Get a random port, concatenate its string with the full url,
|
||||
// and bitwise and its validity result so the result becomes false
|
||||
// if necessary
|
||||
current_rand = random_generator.nextInt(test_ports.length);
|
||||
full_url_string += test_ports[current_rand].item;
|
||||
expected_validity &= test_ports[current_rand].valid;
|
||||
|
||||
// Get a random path, concatenate its string with the full url,
|
||||
// and bitwise and its validity result so the result becomes false
|
||||
// if necessary
|
||||
current_rand = random_generator.nextInt(test_paths.length);
|
||||
full_url_string += test_paths[current_rand].item;
|
||||
expected_validity &= test_paths[current_rand].valid;
|
||||
|
||||
// Get the result of isValid from the url validator
|
||||
Boolean actual_validity = url_validator.isValid(full_url_string);
|
||||
|
||||
// Make a boolean that tells us whether the expected and actual
|
||||
// validities match
|
||||
Boolean validities_match = (actual_validity == expected_validity);
|
||||
|
||||
if (validities_match) {
|
||||
// If they match, increment our success counter.
|
||||
match_count++;
|
||||
|
||||
} else {
|
||||
// Otherwise, print the failed url, and increment our fail count
|
||||
// Here, I also have another call to isValid that can be
|
||||
// uncommented for easy debugging of the failed url
|
||||
System.out.println("Failed on url: " + full_url_string);
|
||||
url_validator.isValid(full_url_string);
|
||||
fail_count++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Print that the test is over
|
||||
System.out.println("Programmatically generated tests complete!");
|
||||
|
||||
// Print the number of successes
|
||||
System.out.println(match_count + " tests succeeded!");
|
||||
|
||||
// If there are failures, print the number of failures and a large
|
||||
// warning.
|
||||
if (fail_count > 0) {
|
||||
System.out.println("SOME TESTS FAILED!!!!");
|
||||
System.out.println(fail_count + " tests failed!");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private ResultPair[] get_result_pairs_from_file(String filename) {
|
||||
// Create some file reading classes
|
||||
FileReader file_reader = null;
|
||||
BufferedReader buffered_reader = null;
|
||||
|
||||
// Get the number of lines that are in the file
|
||||
int num_lines = get_num_lines_in_file(filename);
|
||||
|
||||
// Try and open the file reader on the file or handle exceptions
|
||||
try {
|
||||
file_reader = new FileReader(filename);
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// Put this reader into the buffered reader to make it easy to work with
|
||||
buffered_reader = new BufferedReader(file_reader);
|
||||
|
||||
// Create a result pair array with the correct number of entries
|
||||
ResultPair[] pairs = new ResultPair[num_lines];
|
||||
|
||||
// Variable to hold the current line from the reader
|
||||
String current_line = null;
|
||||
|
||||
// Do and initial read to start off, or handle exceptions
|
||||
try {
|
||||
current_line = buffered_reader.readLine();
|
||||
} catch (IOException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
|
||||
// For the number of lines in the file, loop
|
||||
for (int i = 0; i < num_lines; i++) {
|
||||
// Encapsulate in try block to hand exceptions
|
||||
try {
|
||||
// Split the current line by tabs, so there will be two indexes,
|
||||
// one with the string, and one saying whether it's valid
|
||||
String[] split_by_tab = current_line.split("\\t");
|
||||
|
||||
// Set the name to the first index
|
||||
String name = split_by_tab[0];
|
||||
|
||||
// Create and empty bool for validity
|
||||
Boolean is_valid = null;
|
||||
|
||||
// Check the validity string in index one, and set the validity
|
||||
// boolean accordingly
|
||||
if (split_by_tab[1].equals("valid")) {
|
||||
is_valid = true;
|
||||
} else {
|
||||
is_valid = false;
|
||||
}
|
||||
|
||||
// Set the current index of the result pair array to a new
|
||||
// result pair with the name and validity
|
||||
pairs[i] = new ResultPair(name, is_valid);
|
||||
|
||||
// Read a new line for the next run through the loop
|
||||
current_line = buffered_reader.readLine();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Now we're done, so close the file or handle exceptions
|
||||
try {
|
||||
buffered_reader.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// Return our new array of pairs
|
||||
return pairs;
|
||||
}
|
||||
|
||||
private int get_num_lines_in_file(String filename) {
|
||||
// Create a line number reader
|
||||
LineNumberReader line_reader = null;
|
||||
|
||||
// Make a line reader and handle exceptions
|
||||
try {
|
||||
line_reader = new LineNumberReader(new FileReader(
|
||||
new File(filename)));
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// Skip to the end of the file or handle exceptions
|
||||
try {
|
||||
line_reader.skip(Long.MAX_VALUE);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// Get the number of lines the reader has read. The extra one makes it
|
||||
// one indexed.
|
||||
int number_of_lines = line_reader.getLineNumber() + 1;
|
||||
|
||||
// Close the file, or handle exceptions
|
||||
try {
|
||||
line_reader.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// Return the number of lines we found
|
||||
return number_of_lines;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,10 @@
|
||||
/test1 valid
|
||||
/t123 valid
|
||||
/$23 valid
|
||||
/.. invalid
|
||||
/../ invalid
|
||||
/test1/ valid
|
||||
true
|
||||
/test1/file valid
|
||||
/..//file invalid
|
||||
/test1//file invalid
|
||||
@@ -0,0 +1,7 @@
|
||||
:80 valid
|
||||
:65535 valid
|
||||
:0 valid
|
||||
valid
|
||||
:-1 invalid
|
||||
:65636 valid
|
||||
:65a invalid
|
||||
@@ -0,0 +1,21 @@
|
||||
valid
|
||||
http:// valid
|
||||
https:// valid
|
||||
ftp:// valid
|
||||
file:// valid
|
||||
telnet:// valid
|
||||
tftp:// valid
|
||||
smtp:// valid
|
||||
rtsp:// valid
|
||||
magnet:// valid
|
||||
dns:// valid
|
||||
h3t:// valid
|
||||
:// invalid
|
||||
:/ invalid
|
||||
: invalid
|
||||
/ invalid
|
||||
1:// invalid
|
||||
magnet:/ invalid
|
||||
magnet/ invalid
|
||||
magnet// invalid
|
||||
magnet: invalid
|
||||
Reference in New Issue
Block a user