8000 Add files via upload by imadtg · Pull Request #3 · imadtg/domino-ai · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Add files via upload #3

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
< 8000 div data-target="diff-layout.mainContainer" data-view-component="true" class="Layout-main">
4 changes: 3 additions & 1 deletion cst.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@
#include <string.h>
#include <float.h>

#define BLOCK 0 // block picking from the boneyard, like in the blocking game.
#define PIPS 7 // the number of possible pip numbers, counts from 0 to PIPS-1.
#define MAX_NUM_PLY_MOVE (PIPS*2+1) // max number of possible moves assuming snake is nonempty
#define NP 2 // the number of players, it is 2 for now.
#define DCOUNT ((PIPS*(PIPS+1))/2) // i honestly forgot what these two were for
#define DCOUNT ((PIPS*(PIPS+1))/2) // total number of distinct dominoes
#define LGCOUNT (DCOUNT/2+1) // this is embarassing


#endif
13 changes: 6 additions & 7 deletions game.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,7 @@ int is_passing(Game *g, int player){ // test whether a player will pass if given
void print_game(Game *g){
printf("-------------------------------------------------------------\n");
// print the hands then the snake.
for(int i = 0; i <= NP; i++) {
print_hand(&g->hands, i);
}
print_hands(&g->hands);
print_snake(&g->snake);
// print whose turn it is and the pass counter. also print possible_move moves for the current player.
printf("Turn: %d\n", g->turn);
Expand Down Expand Up @@ -164,19 +162,19 @@ float pick_unplayable_domino_probability_from_moves(Game *g, Move play_perf[], i
}

float pick_unplayable_domino_probability(Game *g, int n_solid, int n_liquid){ // takes how many unplayable dominoes in each group of the boneyard
if(g->hands.hand_sizes[NP] == 0)
if(!boneyard_is_pickable(&g->hands))
return 0.0f;
float solid_prob = (float) n_solid / g->hands.hand_sizes[NP];
float liquid_prob = 0.0f;
if(g->hands.solid_groups[NP].size != 0)
if(g->hands.liquid_groups[NP].size != 0)
liquid_prob = (float) (n_liquid * (g->hands.hand_sizes[NP] - g->hands.solid_groups[NP].size)) / (g->hands.liquid_groups[NP].size * g->hands.hand_sizes[NP]);
return liquid_prob + solid_prob;
}

float pass_probability_from_num_moves(Game *g, int n){
if(g->snake.head == NULL)
return 0.0f;
return pass_probability(g, n - possible_possession(g->turn, &g->hands, g->snake.head->domino.right, g->snake.tail->domino.left));
return pass_probability(g, n - !!possible_possession(g->turn, &g->hands, g->snake.head->domino.right, g->snake.tail->domino.left));
}

float pass_probability(Game *g, int n){ // n is the number of distinct playable dominoes by the player
Expand Down Expand Up @@ -263,7 +261,7 @@ void pass(Game *g){
}

void undo_pass(Game *g, Hands *prev){
g->turn = (g->turn - 1) % NP;
g->turn = (g->turn - 1 + NP) % NP;
g->pass_counter--;
g->hands = *prev;
}
Expand All @@ -272,6 +270,7 @@ void perfect_pick(Game *g, Move move){
if(!hand_is_solid(g->turn, &g->hands))
absent(g);
set_sole_owner_pick(g->turn, &g->hands, move.perfect_pick.left, move.perfect_pick.right);

g->hands.hand_sizes[g->turn]++;
g->hands.hand_sizes[NP]--;
emit_collapse(&g->hands);
Expand Down
16 changes: 16 additions & 0 deletions hands.c
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,14 @@ int hand_is_empty(int player, Hands *hands){
return hands->hand_sizes[player] == 0;
}

int boneyard_is_pickable(Hands *hands){
#if BLOCK
return 0;
#else
return !hand_is_empty(NP, hands);
#endif
}

// perfect boneyard picks
void set_sole_owner_pick(int player, Hands *hands, int i, int j){ // needs not be optimized
if(certain(hands, i, j)){
Expand Down Expand Up @@ -288,6 +296,8 @@ void collapse_hand_evaporate(int player, Hands *hands){

void cascade_collapse(int player, Hands *hands){
if(!collapse_hand(player, hands)) return;
int y = 2;
int x = *(int *)((hands->liquid_groups[0].size >= 0) * (unsigned long long) &y);
for(int p = 0; p <= NP; p++){
if(p != player)
cascade_collapse(p, hands);
Expand Down Expand Up @@ -350,6 +360,12 @@ void print_hand(Hands *hands, int player) {
printf("\nsizes: liquid = %d, solid = %d, true = %d, weights: %d (%d)+ %f (%f)= %f\n", hands->liquid_groups[player].size, hands->solid_groups[player].size, hands->hand_sizes[player], tsw, sw, tlw, lw, weight(hands, player));
}

void print_hands(Hands *hands){
for(int i = 0; i <= NP; i++) {
print_hand(hands, i);
}
}

void get_hand_sizes(Hands *hands) {
// TODO: allow silent games
for(int i = 0; i < NP; i++){
Expand Down
2 changes: 2 additions & 0 deletions hands.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ int sole_owner(Hands *hands, int i, int j);
int hand_is_solid(int player, Hands *hands);
int hand_is_liquid(int player, Hands *hands);
int hand_is_empty(int player, Hands *hands);
int boneyard_is_pickable(Hands *hands);

// Ownership modifications after moves/start
void set_sole_owner_pick(int player, Hands *hands, int i, int j);
Expand All @@ -86,6 +87,7 @@ float weight(Hands *hands, int player);

// Hand print
void print_hand(Hands *hands, int player);
void print_hands(Hands *hands);

// Hand initialization
void get_hand_sizes(Hands *hands);
Expand Down
63 changes: 37 additions & 26 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,32 +14,40 @@ void start(){
printf("Game starts with turn : ");
fflush(stdout);
scanf("%d", &g->turn);
int n, cant_pass, ai_play, skip, depth;
int n, nplypck, npck, cant_pass, ai_play, skip, depth;
float (*ai_function)(Game *, int, int, int *);
float unplayable_prob, pass_prob;
enum Mode ai_mode;
Move moves[DCOUNT], move;
Move moves[DCOUNT], playable_picking_moves[DCOUNT], picking_moves[DCOUNT], move;
do {
print_game(g);
get_playing_moves(g, moves, &n, &cant_pass);
print_playing_moves(moves, n);
printf("%d moves\n", n);
get_playable_perfect_picking_moves(g, playable_picking_moves, &nplypck);
get_perfect_picking_moves(g, picking_moves, &npck);
pass_prob = pass_probability_from_num_moves(g, n);
pass_probability_from_num_moves(g, n);
print_picking_moves(picking_moves, npck);
print_picking_moves(playable_picking_moves, nplypck);
printf("pass prob = %f\n", pass_prob);
unplayable_prob = pick_unplayable_domino_probability_from_moves(g, playable_picking_moves, nplypck);
printf("unplayable pick prob = %f\n", unplayable_prob);
if(cant_pass) printf("cant pass\n");
if(n == 0){
if(g->hands.hand_sizes[NP]){
if(is_passing(g, NP)){
Move pick_all_of_boneyard;
pick_all_of_boneyard.type = IMPERFECT_PICK;
pick_all_of_boneyard.imperfect_pick.count = g->hands.hand_sizes[NP];
imperfect_pick(g, pick_all_of_boneyard);
continue;
}
else if(g->hands.hand_sizes[NP] == 1){
Move pick_one_of_boneyard;
int dummy;
pick_one_of_boneyard.type = PERFECT_PICK;
get_perfect_picking_moves(g, &pick_one_of_boneyard, &dummy); // VERY UNSAFE
perfect_pick(g, pick_one_of_boneyard);
continue;
if(boneyard_is_pickable(&g->hands)){
if(hand_is_solid(NP, &g->hands) || hand_is_liquid(g->turn, &g->hands)){
if(is_passing(g, NP)){
Move pick_all_of_boneyard;
pick_all_of_boneyard.type = IMPERFECT_PICK;
pick_all_of_boneyard.imperfect_pick.count = g->hands.hand_sizes[NP];
imperfect_pick(g, pick_all_of_boneyard);
continue;
}
else if(g->hands.hand_sizes[NP] == 1){
perfect_pick(g, picking_moves[0]);
continue;
}
}
} else {
pass(g);
Expand All @@ -52,9 +60,9 @@ void start(){
if(!cant_pass && n == 0)
printf("give move type (perf pick = %d, imp pick = %d, pass = %d): ", PERFECT_PICK, IMPERFECT_PICK, PASS);
else if(!cant_pass)
printf("give move type (left = %d, right = %d, perf pick = %d, imp pick = %d, pass = %d)(AI def): ", LEFT, RIGHT, PERFECT_PICK, IMPERFECT_PICK, PASS);
printf("give move type (left = %d, right = %d, perf pick = %d, imp pick = %d, pass = %d)(AI = -1): ", LEFT, RIGHT, PERFECT_PICK, IMPERFECT_PICK, PASS);
else
printf("give move type (left = %d, right = %d)(AI def): ", LEFT, RIGHT);
printf("give move type (left = %d, right = %d)(AI = -1): ", LEFT, RIGHT);
scanf("%d", &move.type);
switch(move.type){
case LEFT:
Expand All @@ -67,7 +75,8 @@ void start(){
}
break;
case PERFECT_PICK:
if(cant_pass){
if(cant_pass || !boneyard_is_pickable(&g->hands)){
fflush(stdin);
printf("invalid move\n");
break;
}
Expand All @@ -78,7 +87,8 @@ void start(){
printf("invalid move\n");
break;
case IMPERFECT_PICK:
if(cant_pass){
if(cant_pass || !boneyard_is_pickable(&g->hands)){
fflush(stdin);
printf("invalid move\n");
break;
}
Expand All @@ -95,10 +105,9 @@ void start(){
}
pass(g);
break;
default: // AI move
case -1: // AI move, don't know if i should enumerate in enum Move.
if(n == 0){
printf("reading 4 ints for consistency:");
scanf("%*d %*d %*d %*d");
fflush(stdin);
printf("no moves to choose AI move from\n");
break;
}
Expand Down Expand Up @@ -132,7 +141,9 @@ void start(){

int main(){
init_fact();
start();
getch();
while(1){
start();
getch();
}
return 0;
}
9 changes: 5 additions & 4 deletions minimax.c
9D03
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#include "minimax.h"

int FALLBACK = 0;
volatile int FALLBACK = 0;

WINBOOL interrupt_search(DWORD ctrl_type){
if (ctrl_type == CTRL_C_EVENT) {
Expand Down Expand Up @@ -38,7 +38,7 @@ float pick_loss_evaluation(Game *g){ // the loss of the player who's turn it is
void process_absence(Game *g, Hands *anchor, float *pass_score, float *prob, int n, int depth, int skip, int *nodes, float (*ai_function)(Game *, int, int, int *)){
*prob = pass_probability_from_num_moves(g, n);
if(*prob != 0){
if(!hand_is_empty(NP, &g->hands)){ // we have to handle picking from the boneyard
if(boneyard_is_pickable(&g->hands)){ // we have to handle picking from the boneyard
if(is_passing(g, NP)){ // there is no playable domino left in the boneyard, we will pick it all.
Move pick_all_of_boneyard;
pick_all_of_boneyard.type = IMPERFECT_PICK;
Expand All @@ -65,7 +65,7 @@ void process_absence(Game *g, Hands *anchor, float *pass_score, float *prob, int
undo_perfect_pick(g, anchor);
}
*pass_score /= nperf;
} else {
} else { // TODO: explore imperfect picks of all sizes followed by all playable perfect picks.
Move playable_perfect_picking_moves[MAX_NUM_PLY_MOVE];
int nplayperf;
get_playable_perfect_picking_moves(g, playable_perfect_picking_moves, &nplayperf);
Expand All @@ -79,13 +79,14 @@ void process_absence(Game *g, Hands *anchor, float *pass_score, float *prob, int
pick_playable_score += ai_function(g, depth - 1, skip, nodes);
undo_perfect_pick(g, anchor);
}
if(!nplayperf) printf("uh oh");
pick_playable_score /= nplayperf;
if(unplayable_prob != 0){
Move pick_unplayable;
pick_unplayable.type = IMPERFECT_PICK;
pick_unplayable.imperfect_pick.count = 1;
imperfect_pick(g, pick_unplayable);
pick_unplayable_score = ai_function(g, depth, skip, nodes);
pick_unplayable_score = ai_function(g, depth - 1 ,skip, nodes);
undo_imperfect_pick(g, anchor);
}
*pass_score = unplayable_prob * pick_unplayable_score + (1 - unplayable_prob) * pick_playable_score;
Expand Down
2 changes: 1 addition & 1 deletion minimax.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

enum Mode {PESSIMIST, EXPECT};

extern int FALLBACK;
extern volatile int FALLBACK;

WINBOOL interrupt_search(DWORD ctrl_type);
float endgame_evaluation(Game *g);
Expand Down
0