previndexinfonext

code guessing, round #45 (completed)

started at ; stage 2 at ; ended at

specification

yawn. play connect four. any language.

connect four is a game. there is a grid. the grid has 7 columns and 6 rows. there are two players. each has a colour of piece they put on the grid. they take turns making moves. to make a move, you pick a non-full column and put a piece of your colour on the lowest empty space on that column. if you form a diagonal, vertical or horizontal line of 4 pieces of your colour, you win the game. otherwise, the next person plays. if the grid is full, the game is a tie.

the interface is simple. your program starts. it reads either an s or an f from stdin, followed by a newline.

if the character was s, it goes second. it reads an ascii digit from 1 to 7 from stdin, followed by a newline. it updates its internal state to reflect that the other player has played this move. the program continues to run. it writes an ascii digit from 1 to 7 to stdout, followed by a newline. the program continues to run. it reads another move and continues ad infinitum. once the game is over, any further behaviour is not specified.

if the character was f, it goes first. it writes an ascii digit from 1 to 7 to stdout, followed by a newline. this represents its first move. the following behaviour is the same as s.

the newlines are required in the hopes that they will make buffering work correctly, as streams should be line-buffered by default. they are very important. do not forget to include and read them.

your challenge is to implement such a program. your program must be executable from an environment with standard io streams and have the exact interface as described above. it does not have to play connect four optimally. it only has to play. all moves output must be valid. all moves received will be valid. there is no otherwise. otherwise is undefined.

results

  1. 👑 LyricLy +5 -1 = 4
    1. soup girl (was IFcoltransG)
    2. Olivia
    3. yui (was Cow Bandit)
    4. JJRubes (was Amanda)
    5. luatic (was kimapr)
    6. kimapr (was yui)
    7. taswelll
    8. razetime (was luatic)
    9. vspf
    10. IFcoltransG (was JJRubes)
    11. moshikoi
    12. Amanda (was razetime)
    13. Cow Bandit (was soup girl)
    14. jetison333
  2. luatic +5 -3 = 2
    1. razetime (was IFcoltransG)
    2. Olivia
    3. vspf (was Cow Bandit)
    4. soup girl (was Amanda)
    5. kimapr
    6. yui
    7. IFcoltransG (was taswelll)
    8. moshikoi (was vspf)
    9. LyricLy
    10. taswelll (was JJRubes)
    11. JJRubes (was moshikoi)
    12. Cow Bandit (was razetime)
    13. Amanda (was soup girl)
    14. jetison333
  3. razetime +3 -1 = 2
    1. soup girl (was IFcoltransG)
    2. Olivia
    3. jetison333 (was Cow Bandit)
    4. JJRubes (was Amanda)
    5. kimapr
    6. yui
    7. moshikoi (was taswelll)
    8. LyricLy (was luatic)
    9. IFcoltransG (was vspf)
    10. Amanda (was LyricLy)
    11. Cow Bandit (was JJRubes)
    12. luatic (was moshikoi)
    13. taswelll (was soup girl)
    14. vspf (was jetison333)
  4. vspf +4 -3 = 1
    1. IFcoltransG
    2. soup girl (was Olivia)
    3. taswelll (was Cow Bandit)
    4. Cow Bandit (was Amanda)
    5. kimapr
    6. razetime (was yui)
    7. LyricLy (was taswelll)
    8. luatic
    9. Amanda (was LyricLy)
    10. JJRubes
    11. yui (was moshikoi)
    12. Olivia (was razetime)
    13. jetison333 (was soup girl)
    14. moshikoi (was jetison333)
  5. yui +3 -2 = 1
    1. jetison333 (was IFcoltransG)
    2. Olivia
    3. razetime (was Cow Bandit)
    4. LyricLy (was Amanda)
    5. Amanda (was kimapr)
    6. kimapr (was taswelll)
    7. JJRubes (was luatic)
    8. vspf
    9. IFcoltransG (was LyricLy)
    10. Cow Bandit (was JJRubes)
    11. luatic (was moshikoi)
    12. moshikoi (was razetime)
    13. soup girl
    14. taswelll (was jetison333)
  6. Cow Bandit +1 -0 = 1
    1. JJRubes (was IFcoltransG)
    2. IFcoltransG (was Olivia)
    3. moshikoi (was Amanda)
    4. jetison333 (was kimapr)
    5. Amanda (was yui)
    6. kimapr (was taswelll)
    7. luatic
    8. LyricLy (was vspf)
    9. vspf (was LyricLy)
    10. Olivia (was JJRubes)
    11. razetime (was moshikoi)
    12. soup girl (was razetime)
    13. taswelll (was soup girl)
    14. yui (was jetison333)
  7. jetison333 +2 -2 = 0
    1. luatic (was IFcoltransG)
    2. razetime (was Olivia)
    3. yui (was Cow Bandit)
    4. Amanda
    5. kimapr
    6. IFcoltransG (was yui)
    7. LyricLy (was taswelll)
    8. soup girl (was luatic)
    9. moshikoi (was vspf)
    10. vspf (was LyricLy)
    11. Cow Bandit (was JJRubes)
    12. taswelll (was moshikoi)
    13. Olivia (was razetime)
    14. JJRubes (was soup girl)
  8. Amanda +2 -2 = 0
    1. LyricLy (was IFcoltransG)
    2. taswelll (was Olivia)
    3. jetison333 (was Cow Bandit)
    4. soup girl (was kimapr)
    5. vspf (was yui)
    6. razetime (was taswelll)
    7. luatic
    8. kimapr (was vspf)
    9. moshikoi (was LyricLy)
    10. JJRubes
    11. Cow Bandit (was moshikoi)
    12. Olivia (was razetime)
    13. yui (was soup girl)
    14. IFcoltransG (was jetison333)
  9. taswelll +1 -1 = 0
    1. soup girl (was IFcoltransG)
    2. luatic (was Olivia)
    3. jetison333 (was Cow Bandit)
    4. JJRubes (was Amanda)
    5. Olivia (was kimapr)
    6. Cow Bandit (was yui)
    7. kimapr (was luatic)
    8. LyricLy (was vspf)
    9. moshikoi (was LyricLy)
    10. Amanda (was JJRubes)
    11. IFcoltransG (was moshikoi)
    12. razetime
    13. vspf (was soup girl)
    14. yui (was jetison333)
  10. kimapr +3 -4 = -1
    1. Cow Bandit (was IFcoltransG)
    2. Olivia
    3. taswelll (was Cow Bandit)
    4. Amanda
    5. vspf (was yui)
    6. soup girl (was taswelll)
    7. yui (was luatic)
    8. jetison333 (was vspf)
    9. moshikoi (was LyricLy)
    10. JJRubes
    11. razetime (was moshikoi)
    12. LyricLy (was razetime)
    13. IFcoltransG (was soup girl)
    14. luatic (was jetison333)
  11. IFcoltransG +0 -1 = -1
    1. moshikoi +0 -1 = -1
      1. JJRubes +1 -3 = -2
        1. vspf (was IFcoltransG)
        2. moshikoi (was Olivia)
        3. razetime (was Cow Bandit)
        4. taswelll (was Amanda)
        5. luatic (was kimapr)
        6. LyricLy (was yui)
        7. Amanda (was taswelll)
        8. jetison333 (was luatic)
        9. yui (was vspf)
        10. Olivia (was LyricLy)
        11. kimapr (was moshikoi)
        12. Cow Bandit (was razetime)
        13. soup girl
        14. IFcoltransG (was jetison333)
      2. soup girl +0 -2 = -2
        1. Olivia +1 -5 = -4
          1. LyricLy (was IFcoltransG)
          2. yui (was Cow Bandit)
          3. JJRubes (was Amanda)
          4. moshikoi (was kimapr)
          5. Cow Bandit (was yui)
          6. soup girl (was taswelll)
          7. Amanda (was luatic)
          8. vspf
          9. kimapr (was LyricLy)
          10. jetison333 (was JJRubes)
          11. taswelll (was moshikoi)
          12. luatic (was razetime)
          13. razetime (was soup girl)
          14. IFcoltransG (was jetison333)

        entries

        you can download all the entries

        entry #1

        written by IFcoltransG
        submitted at
        0 likes

        guesses
        comments 0

        post a comment


        INDEFATIGABLE.hs ASCII text, with no line terminators
        1
        import Control.Monad; main = getLine >>= (`when` putStrLn "1") . ("f" ==) >> interact (unlines . (++ [""]) . fmap (show . succ . (`mod` 7) . read) . lines) -- breaks when enemy s plays x=7, y=6
        

        entry #2

        written by Olivia
        submitted at
        2 likes

        guesses
        comments 0

        post a comment


        stockbird.py Unicode text, UTF-8 text
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        import subprocess, re, time, time # and time again
        square_shape = [[] for _ in list("olivia!")]
        assertively = lambda s: (tell(s), exchange("isready", "readyok"))
        confidante = subprocess.Popen(["stockfish"], text=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
        utterings = lambda: re.sub("1+", lambda n: str(len(n[0])), "k6K/8/" + ''.join("".join(["1pP"[square.count(",")] for square in (rectangle + list("esolangs"))[:8]]) + "1/" for rectangle in square_shape))
        exchange = lambda s, t: (tell(s), ought(t))
        rumours = lambda s: (lambda g: g[1] if g[1] else rumours(s))(gather(s))
        gather = lambda s: (lambda x: (lambda y: (x, y[1] if y else y))(re.match(s + "\n", x)))(get())
        ought = lambda s: list(iter(get, s + "\n"))
        tell = lambda s: (confidante.stdin.write(s + "\n"), confidante.stdin.flush()) # 😳
        get = confidante.stdout.readline
        me = lambda s: (square_shape[s].append("vampire teef ,..,"), print(s + 1))
        u = lambda: square_shape[int(input()) - 1].append("it's me, olivia")
        if input() == 's': u()
        exchange("uci", "uciok")
        while ~ True:
           assertively("ucinewgame")
           assertively("position fen " + utterings() + "moves")
           tell("go depth 1")
           time.sleep(1)
           tell("stop")
           wishes = int(rumours("bestmove [^\s]+?(\d)")) % 7
           try:
               while len(square_shape[wishes]) >= 6: wishes += 1
           except BaseException as e:
               raise BaseException("congratulations, you win!") from e
           me(wishes)
           u()
        

        entry #3

        written by Cow Bandit
        submitted at
        0 likes

        guesses
        comments 1
        twelve bees

        bzzzzzzzz


        post a comment


        connectfour.py ASCII text, with CRLF line terminators
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        import sys
        x=4
        y=[]
        for i in range(695,7045):
            x=(x<<4)-365
            x//=11
            x*=3
            x=abs(x)
            y.append(x%7)
        james=sys.stdin.readline()
        match james:
            case 's\n':   #second
                james=int(sys.stdin.readline())
            case 'f\n'|'a\n'|'H\n'|_: #first/a/H
                pass
        while(True):
            for i in y:
                print(i+True)
                james=int(sys.stdin.readline())
        

        entry #4

        written by Amanda
        submitted at
        1 like

        guesses
        comments 0

        post a comment


        connect-four.c Unicode text, UTF-8 text
          1
          2
          3
          4
          5
          6
          7
          8
          9
         10
         11
         12
         13
         14
         15
         16
         17
         18
         19
         20
         21
         22
         23
         24
         25
         26
         27
         28
         29
         30
         31
         32
         33
         34
         35
         36
         37
         38
         39
         40
         41
         42
         43
         44
         45
         46
         47
         48
         49
         50
         51
         52
         53
         54
         55
         56
         57
         58
         59
         60
         61
         62
         63
         64
         65
         66
         67
         68
         69
         70
         71
         72
         73
         74
         75
         76
         77
         78
         79
         80
         81
         82
         83
         84
         85
         86
         87
         88
         89
         90
         91
         92
         93
         94
         95
         96
         97
         98
         99
        100
        101
        102
        103
        104
        105
        106
        107
        108
        109
        110
        111
        112
        113
        114
        115
        116
        117
        118
        119
        120
        121
        122
        123
        124
        125
        126
        127
        128
        129
        130
        131
        132
        133
        134
        135
        136
        137
        138
        139
        140
        141
        142
        143
        144
        145
        146
        147
        148
        149
        150
        151
        152
        153
        154
        155
        156
        157
        158
        159
        160
        161
        162
        163
        164
        165
        166
        167
        168
        169
        170
        171
        172
        173
        174
        175
        176
        177
        178
        179
        180
        181
        182
        183
        184
        185
        186
        187
        188
        189
        190
        191
        192
        193
        194
        195
        196
        197
        198
        199
        200
        201
        202
        203
        204
        205
        206
        207
        208
        209
        210
        211
        212
        213
        214
        215
        216
        217
        218
        219
        220
        221
        222
        223
        224
        225
        226
        227
        228
        229
        230
        231
        232
        233
        234
        235
        236
        237
        238
        239
        240
        241
        242
        243
        244
        245
        246
        247
        248
        249
        250
        251
        252
        253
        254
        255
        256
        257
        258
        259
        260
        261
        262
        263
        264
        265
        266
        267
        268
        269
        270
        271
        272
        273
        274
        275
        276
        277
        278
        279
        280
        281
        282
        283
        284
        285
        286
        287
        288
        289
        290
        291
        // Copyleft 2007-2023 <redacted>
        // To compile: `gcc connect-four.c -o connect-four`
        
        #include <stdlib.h>
        #include <math.h>
        #include <stdio.h>
        #include <stdbool.h>
        #include <time.h>
        
        typedef struct Vec2 {
        	int x;
        	int y;
        } Vec2;
        
        int broad[7][6];
        
        #define WIN_DRAW -1
        #define WIN_TBA 0
        #define WIN_PLAYER 1
        #define WIN_COMPUTER 2
        
        bool looping = true;
        int win = WIN_TBA;
        
        void dramaticExit() {
        	for (size_t i = 0; i < 420; i++) { printf("WHAT?????????????????????????"); }
        
        	int lol = 423;
        	printf(lol);
        	// BOOM
        }
        
        void drawboard() {
        	system("clear");
        	for (int i = 5; i > -1; i--) {
        		for (int j = 0; j < 7; j++) {
        			if (broad[j][i] == 1) {
        				printf("| X ");
        			}else if (broad[j][i] == 2) {
        				printf("| O ");
        			} else if (broad[j][i] == 3) {
        				printf("|@@@");
        			} else {
        				printf("|   ");
        			}
        		}
        		printf("|");
        		printf("\n+---+---+---+---+---+---+---+\n");
        	}
        }
        
        
        int sterilize(char car) {
        	switch (car) {
        		case '1': return 1;
        		case '2': return 2;
        		case '3': return 3;
        		case '4': return 4;
        		case '5': return 5;
        		case '6': return 6;
        		case '7': return 7;
        		case 10: return -1;
        		default: dramaticExit(); break;
        	}
        }
        
        bool checkfilled() {
        	for (int i = 5; i > -1; i--) {
        		for (int j = 0; j < 7; j++) {
        			if (broad[j][i]) {
        				return false;
        			}
        		}
        	}
        
        	win = WIN_DRAW;
        	return true;
        }
        
        bool checksuccess(int x, int y, int individual) {
        	bool prevhad = false;
        	int streamlen;
        
        	for (int i = 0; i < 7; i++) {
        		if (!prevhad)
        			streamlen = 0;
        
        		prevhad = (broad[i][y] == individual);
        		if (prevhad) {
        			streamlen++;
        
        			if (streamlen >= 4) return true;
        		}
        	}
        
        	prevhad = false;
        
        	for (int i = 0; i < 6; i++) {
        		if (!prevhad)
        			streamlen = 0;
        
        		prevhad = (broad[x][i] == individual);
        		if (prevhad) {
        			streamlen++;
        
        			if (streamlen >= 4) return true;
        		}
        	}
        
        	prevhad = false;
        
        	Vec2 temp = {x,y};
        
        	while (true) {
        		if (temp.x == 0 || temp.y == 0) {
        			break;
        		}
        
        		temp.x--;
        		temp.y--;
        	}
        
        	for (int i = 0; i < 420; i++) {
        		if (!prevhad)
        			streamlen = 0;
        
        		if (temp.x+i > 7 || temp.y+i > 6) {
        			break;
        		}
        
        		prevhad = (broad[temp.x+i][temp.y+i] == individual);
        		if (prevhad) {
        			streamlen++;
        
        			if (streamlen >= 4) return true; // COOL
        		}
        	}
        
        	prevhad = false;
        	temp.x = x; temp.y = y;
        
        	while (true) {
        		if (temp.x == 6 || temp.y == 0) {
        			break;
        		}
        
        		temp.x++;
        		temp.y--;
        	}
        
        	for (int i = 0; i < 99; i++) {
        		if (!prevhad)
        			streamlen = 0;
        
        		if (temp.x+i < 0 || temp.y+i > 6) {
        			// HMM
        			break;
        		}
        
        		prevhad = (broad[temp.x-i][temp.y+i] == individual);
        		if (prevhad) {
        			streamlen++;
        
        			if (streamlen >= 4) return true;
        		}
        	}
        
        	return false;
        }
        
        Vec2 place(int choice) {
        	if (choice == -1) {
        		// BRUH
        		dramaticExit();
        	}
        
        	int hasplaced = 0;
        
        	for (int i = 0; i < 6; i++) {
        		if (broad[choice-1][i] == 0) {
        			broad[choice-1][i] = 1;
        			Vec2 pos = { choice-1, i };
        			return pos;
        		}
        	}
        }
        
        Vec2 artificialstupidity() {
        	while (true) {
        		int aichoice = (rand()%6)+1;
        
        		for (int i = 0; i < 6; i++) {
        			if (broad[aichoice-1][i] == 0) {
        				broad[aichoice-1][i] = 2;
        				Vec2 pos = { aichoice-1, i };
        				return pos;
        			}
        		}
        	}
        }
        
        int cool() {
        	srand(time(NULL));
        
        	for(int i = 0; i < 7; i++){
        		for(int j = 0; j < 6; j++){
        			broad[i][j] = 0;
        		}
        	}
        
        	char car,intro;
        	int choice;
        	bool playersuccess, aisuccess;
        
        	printf(" ██████╗ ██████╗ ███╗   ██╗      ██╗  ██╗\n");
        	printf("██╔════╝██╔═══██╗████╗  ██║      ██║  ██║\n");
        	printf("██║     ██║   ██║██╔██╗ ██║█████╗███████║\n");
        	printf("██║     ██║   ██║██║╚██╗██║╚════╝╚════██║\n");
        	printf("╚██████╗╚██████╔╝██║ ╚████║           ██║\n");
        	printf(" ╚═════╝ ╚═════╝ ╚═╝  ╚═══╝           ╚═╝\n");
        	printf("==--==--==--==--==-==--==--==--==--==--==\n");
        	printf("Select if you wan to go first or secoond:\n");
        
        	// can i haz char
        	intro = getchar();
        
        	// artificial stupidity takes one for the team
        	if (intro == 's') {
        		Vec2 aipos = artificialstupidity();
        	}
        
        	while (win == WIN_TBA) {
        		drawboard();
        
        		car = getchar();
        
        		choice = sterilize(car);
        
        		if (choice != -1) {
        			Vec2 placepos = place(choice);
        
        			playersuccess = checksuccess(placepos.x, placepos.y, 1);
        
        			if (playersuccess) {
        				win = WIN_PLAYER;
        				drawboard();
        				break;
        			}
        
        			checkfilled();
        
        			Vec2 aipos = artificialstupidity();
        
        			aisuccess = checksuccess(aipos.x, aipos.y, 2);
        
        			if (aisuccess) {
        				win = WIN_COMPUTER;
        				drawboard();
        				break;
        			}
        
        			checkfilled();
        		}
        	}
        
        	switch (win) {
        		case WIN_DRAW:
        			printf("Nobody won... Thanks for playing.\n");
        			return WIN_DRAW;
        		case WIN_PLAYER:
        			printf("You won... Thanks for playing.\n");
        			return WIN_PLAYER;
        		case WIN_COMPUTER:
        			printf("Computer won... Thanks for playing.\n");
        			return WIN_COMPUTER;
        	}
        }
        
        int main(void)
        {
        /*#ifndef _WIN32
         // I change my mind, but windows cool
        	printf("please install install windows 10: \n");
        	printf("https://www.microsoft.com/de-de/software-download/windows10ISO");
        	return 69;
        #else*/
        	int ret = cool();
        /*#endif*/
        
        	return ret;
        }
        

        entry #5

        written by kimapr
        submitted at
        1 like

        guesses
        comments 0

        post a comment


        dir parafour
        dir src
        bot.rs ASCII text
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
        44
        45
        46
        47
        48
        49
        50
        51
        52
        53
        54
        55
        56
        57
        58
        59
        60
        61
        62
        63
        64
        65
        66
        67
        68
        69
        70
        71
        72
        73
        74
        75
        use crate::game::*;
        use rand::seq::IteratorRandom;
        use rayon::prelude::*;
        use std::cmp::Ordering;
        use std::mem::swap;
        
        pub trait Bottable<P: GamePlayer, M: GameMove>: Game<P, M> {
            fn random_move(&self) -> Option<M> {
                let mut rng = rand::thread_rng();
                return self.moves().choose(&mut rng);
            }
            fn best_move(&self) -> Option<M> {
                let p = self.current_player();
                let moves = self.moves().collect::<Vec<M>>();
                if moves.is_empty() {
                    return None;
                } else if moves.len() == 1 {
                    return moves.into_iter().next();
                }
                let mut score: Vec<f64> = vec![0.0; moves.len()];
                let mut weights: Vec<f64> = vec![0.0; moves.len()];
                let mut weights_old: Vec<f64> = vec![0.0; moves.len()];
                loop {
                    (&moves).into_par_iter().zip(&mut score).for_each(|(m, c)| {
                        *c += (0..2048)
                            .into_par_iter()
                            .map(|_| self.clone())
                            .map(|mut game| {
                                let mut m = *m;
                                loop {
                                    match game.apply(m).unwrap() {
                                        MoveOutcome::Win(p2) => break if p2 == p { 1.0 } else { -1.0 },
                                        MoveOutcome::Tie => break 0.0,
                                        MoveOutcome::Pass => (),
                                    }
                                    m = game.random_move().unwrap();
                                }
                            })
                            .sum::<f64>();
                    });
                    let min_score = score.iter().copied().reduce(f64::min).unwrap();
                    (&mut weights)
                        .into_iter()
                        .zip(&score)
                        .for_each(|(c, s)| *c = s - min_score);
                    let total: f64 = weights.iter().copied().sum::<f64>();
                    // normalize scores
                    if total > 0.0 {
                        (&mut weights).into_iter().for_each(|c| *c /= total);
                    } else {
                        (&mut weights).into_iter().for_each(|c| *c = 0.0);
                    }
                    let deviation: f64 = weights
                        .iter()
                        .copied()
                        .zip(weights_old.iter().copied())
                        .max_by(|(a, _), (b, _)| a.partial_cmp(b).unwrap_or(Ordering::Equal))
                        .map(|(s, s_old)| f64::abs(s - s_old))
                        .unwrap();
                    if deviation < (1.0 / f64::powf(2.0, 12.0)) {
                        break Some(
                            moves
                                .into_iter()
                                .zip(weights)
                                .max_by(|(_, a), (_, b)| a.partial_cmp(b).unwrap_or(Ordering::Equal))
                                .unwrap()
                                .0,
                        );
                    }
                    swap(&mut weights, &mut weights_old);
                }
            }
        }
        
        impl<P: GamePlayer, M: GameMove, T: Game<P, M>> Bottable<P, M> for T {}
        
        four.rs ASCII text
          1
          2
          3
          4
          5
          6
          7
          8
          9
         10
         11
         12
         13
         14
         15
         16
         17
         18
         19
         20
         21
         22
         23
         24
         25
         26
         27
         28
         29
         30
         31
         32
         33
         34
         35
         36
         37
         38
         39
         40
         41
         42
         43
         44
         45
         46
         47
         48
         49
         50
         51
         52
         53
         54
         55
         56
         57
         58
         59
         60
         61
         62
         63
         64
         65
         66
         67
         68
         69
         70
         71
         72
         73
         74
         75
         76
         77
         78
         79
         80
         81
         82
         83
         84
         85
         86
         87
         88
         89
         90
         91
         92
         93
         94
         95
         96
         97
         98
         99
        100
        101
        102
        103
        104
        105
        106
        107
        108
        109
        110
        111
        112
        113
        114
        115
        116
        117
        118
        119
        120
        121
        122
        123
        124
        125
        126
        127
        128
        129
        130
        131
        132
        133
        134
        135
        136
        137
        138
        139
        140
        141
        142
        143
        144
        145
        146
        147
        use crate::game::*;
        use std::fmt;
        
        #[derive(Clone)]
        pub struct Four<P> {
            player: P,
            data: [(u8, [Option<P>; 6]); 7],
            filled: u8,
            done: bool,
        }
        
        impl<P: GamePlayer + fmt::Display> fmt::Display for Four<P> {
            fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("\n")?;
                for y in (0..6).rev() {
                    formatter.write_str(" ")?;
                    for x in 0..7 {
                        match self.data[x].1[y] {
                            Some(p) => formatter.write_fmt(format_args!("{} ", &p)),
                            None => formatter.write_fmt(format_args!(". ")),
                        }?;
                    }
                    formatter.write_str("\n")?;
                }
                formatter.write_str(" ")?;
                for x in 0..7 {
                    formatter.write_fmt(format_args!("{} ", x + 1))?;
                }
                formatter.write_str("\n")?;
                Ok(())
            }
        }
        
        #[derive(Copy, Clone)]
        pub struct FourMove(u8);
        impl GameMove for FourMove {}
        impl fmt::Display for FourMove {
            fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                (self.0 + 1).fmt(formatter)
            }
        }
        impl TryFrom<u8> for FourMove {
            type Error = ();
            fn try_from(num: u8) -> Result<Self, ()> {
                if num >= 1 && num <= 7 {
                    Ok(Self(num - 1))
                } else {
                    Err(())
                }
            }
        }
        
        pub struct FourMoves<'a, P: 'a> {
            cols: std::iter::Enumerate<std::slice::Iter<'a, (u8, [Option<P>; 6])>>,
            size: usize,
        }
        
        impl<'a, P: GamePlayer> Iterator for FourMoves<'a, P> {
            type Item = FourMove;
            fn next(&mut self) -> Option<Self::Item> {
                let r = self.cols.find(|(_, d)| d.0 < 6).map(|(x, _)| {
                    self.size -= 1;
                    FourMove(x as u8)
                });
                r
            }
            fn size_hint(&self) -> (usize, Option<usize>) {
                (self.size, Some(self.size))
            }
        }
        
        impl<P: GamePlayer> Four<P> {
            const DIRS: [[[i8; 2]; 2]; 4] = [
                [[0, -1], [0, 1]],
                [[-1, 0], [1, 0]],
                [[-1, -1], [1, 1]],
                [[1, -1], [-1, 1]],
            ];
            pub fn new() -> Self {
                Self {
                    player: P::first(),
                    data: [(0, [None; 6]); 7],
                    filled: 0,
                    done: false,
                }
            }
        }
        
        impl<P: GamePlayer> Game<P, FourMove> for Four<P> {
            type Moves<'a> = FourMoves<'a, P> where P: 'a;
            fn current_player(&self) -> P {
                self.player
            }
            fn moves<'a>(&'a self) -> Self::Moves<'a> {
                FourMoves {
                    cols: self.data.iter().enumerate(),
                    size: self.data.iter().filter(|d| d.0 < 6).count(),
                }
            }
            fn apply(&mut self, m: FourMove) -> Option<MoveOutcome<P>> {
                use MoveOutcome::*;
                if self.done {
                    return None;
                }
                let x = m.0;
                if x >= 7 {
                    return None;
                }
                let col = &mut self.data[x as usize];
                if col.0 >= 6 {
                    return None;
                }
                let y = col.0;
                col.1[y as usize] = Some(self.player);
                col.0 += 1;
                self.filled += 1;
                for axis in Self::DIRS.iter() {
                    let mut count = 1;
                    for dir in axis.iter() {
                        let (mut x, mut y) = (x as i8, y as i8);
                        loop {
                            (x, y) = (x + dir[0], y + dir[1]);
                            if x < 0
                                || x >= 7
                                || y < 0
                                || y >= 6
                                || self.data[x as usize].1[y as usize].map_or(true, |p| p != self.player)
                            {
                                break;
                            }
                            count += 1;
                            if count >= 4 {
                                self.done = true;
                                return Some(Win(self.player));
                            }
                        }
                    }
                }
                self.player = self.player.next();
                Some(if self.filled >= 6 * 7 {
                    self.done = true;
                    Tie
                } else {
                    Pass
                })
            }
        }
        
        game.rs ASCII text
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        #[derive(Debug)]
        pub enum MoveOutcome<P> {
            Win(P),
            Tie,
            Pass,
        }
        
        pub trait GamePlayer: Copy + Clone + Eq + Send + Sync {
            fn first() -> Self;
            fn next(&self) -> Self;
        }
        
        pub trait GameMove: Copy + Clone + Send + Sync {}
        
        pub trait Game<P: GamePlayer, M: GameMove>: Clone + Send + Sync {
            type Moves<'a>: Iterator<Item = M> + Sized
            where
                Self: 'a;
            fn current_player(&self) -> P;
            fn moves<'a>(&'a self) -> Self::Moves<'a>;
            fn apply(&mut self, m: M) -> Option<MoveOutcome<P>>;
        }
        
        main.rs ASCII text
          1
          2
          3
          4
          5
          6
          7
          8
          9
         10
         11
         12
         13
         14
         15
         16
         17
         18
         19
         20
         21
         22
         23
         24
         25
         26
         27
         28
         29
         30
         31
         32
         33
         34
         35
         36
         37
         38
         39
         40
         41
         42
         43
         44
         45
         46
         47
         48
         49
         50
         51
         52
         53
         54
         55
         56
         57
         58
         59
         60
         61
         62
         63
         64
         65
         66
         67
         68
         69
         70
         71
         72
         73
         74
         75
         76
         77
         78
         79
         80
         81
         82
         83
         84
         85
         86
         87
         88
         89
         90
         91
         92
         93
         94
         95
         96
         97
         98
         99
        100
        101
        102
        103
        104
        105
        106
        107
        108
        109
        110
        111
        112
        113
        114
        115
        116
        117
        118
        119
        120
        121
        122
        123
        124
        125
        126
        127
        128
        129
        130
        131
        132
        133
        134
        135
        136
        137
        138
        139
        140
        141
        142
        143
        144
        145
        146
        mod bot;
        mod four;
        mod game;
        mod pl2;
        
        use bot::Bottable;
        use crossterm::tty::IsTty;
        use four::{Four, FourMove};
        use game::*;
        use pl2::BinaryPlayer;
        use std::io::{self, BufRead, Write};
        
        #[derive(Debug)]
        enum Miscommunication {
            Io(io::Error),
            MoveParse,
            ModeParse,
        }
        
        impl From<io::Error> for Miscommunication {
            fn from(error: io::Error) -> Self {
                Self::Io(error)
            }
        }
        
        fn handle_outcome<P: GamePlayer>(mmeee: P, out: MoveOutcome<P>) -> (&'static str, bool) {
            match out {
                MoveOutcome::Win(p) => (
                    if p == mmeee {
                        "YIPPIEE I WINNER"
                    } else {
                        "nuuuu :("
                    },
                    false,
                ),
                MoveOutcome::Tie => ("meh", false),
                MoveOutcome::Pass => ("...", true),
            }
        }
        
        fn apply_debugged<P: GamePlayer, M: GameMove, T: Game<P, M> + std::fmt::Display>(
            mmeee: P,
            game: &mut T,
            m: M,
            istty: bool,
        ) -> bool {
            let (msg, out) = handle_outcome(mmeee, game.apply(m).expect("unexpected move failure"));
            if istty {
                eprintln!("{}{}", &game, msg);
            }
            out
        }
        
        use clap::Parser;
        
        #[derive(Parser, Debug)]
        #[command(author, version, about, long_about = None)]
        struct Args {
            #[arg(short, long)]
            quite: bool,
            #[arg(short, long)]
            load: bool,
        }
        
        fn main() -> Result<(), Miscommunication> {
            let args = Args::parse();
            assert!(
                !(args.quite && args.load),
                "can't be load and quite at once..."
            );
            let mut game: Four<BinaryPlayer> = Four::new();
            let reader = io::stdin();
            let mut stdout = io::stdout();
            let istty = if !(args.quite || args.load) {
                reader.is_tty()
            } else {
                args.load
            };
            let mut reader = reader.lock().lines();
            let mmeee;
            loop {
                if istty {
                    eprint!("> ");
                }
                match reader.next().ok_or(Miscommunication::ModeParse)??.as_str() {
                    "f" => {
                        mmeee = BinaryPlayer::first();
                        let m = game.best_move().expect("first move fail");
                        println!("{}", m);
                        stdout.flush()?;
                        assert!(
                            apply_debugged(mmeee, &mut game, m, istty),
                            "first move fail"
                        );
                        break;
                    }
                    "s" => {
                        mmeee = BinaryPlayer::first().next();
                        if istty {
                            eprintln!("{}", &game);
                        }
                        break;
                    }
                    _ => {
                        if istty {
                            eprintln!("bad mode");
                        }
                    }
                }
            }
            let mut reader = reader.map(|l| l.map(|s| s.parse::<u8>()));
            loop {
                loop {
                    let m = loop {
                        if istty {
                            eprint!("{}> ", game.current_player());
                        }
                        let num = reader.next().ok_or(Miscommunication::MoveParse)??.ok();
                        if let Some(m) = num.map(|num| FourMove::try_from(num).ok()).flatten() {
                            break m;
                        }
                    };
                    let out = game.apply(m);
                    match out {
                        Some(out) => {
                            let (msg, out) = handle_outcome(mmeee, out);
                            if !out {
                                if istty {
                                    eprintln!("{}{}", &game, msg);
                                }
                                return Ok(());
                            }
                            break;
                        }
                        None => (),
                    }
                }
                let m = game.best_move().expect("no moves");
                println!("{}", m);
                stdout.flush()?;
                if !apply_debugged(mmeee, &mut game, m, istty) {
                    break;
                }
            }
            Ok(())
        }
        
        pfdm.rs ASCII text
          1
          2
          3
          4
          5
          6
          7
          8
          9
         10
         11
         12
         13
         14
         15
         16
         17
         18
         19
         20
         21
         22
         23
         24
         25
         26
         27
         28
         29
         30
         31
         32
         33
         34
         35
         36
         37
         38
         39
         40
         41
         42
         43
         44
         45
         46
         47
         48
         49
         50
         51
         52
         53
         54
         55
         56
         57
         58
         59
         60
         61
         62
         63
         64
         65
         66
         67
         68
         69
         70
         71
         72
         73
         74
         75
         76
         77
         78
         79
         80
         81
         82
         83
         84
         85
         86
         87
         88
         89
         90
         91
         92
         93
         94
         95
         96
         97
         98
         99
        100
        101
        102
        103
        104
        105
        106
        107
        108
        109
        110
        111
        112
        113
        114
        115
        116
        117
        118
        119
        120
        121
        122
        123
        124
        mod four;
        mod game;
        mod pl2;
        use four::*;
        use game::*;
        use pl2::*;
        
        use clap::Parser;
        use std::ffi::{OsStr, OsString};
        use std::io::{self, BufRead, BufReader, Write};
        use std::mem::drop;
        use std::process::{Child, ChildStdin, ChildStdout, Command, Stdio};
        
        struct Bot {
            pub proc: Child,
            pub read: Option<BufReader<ChildStdout>>,
            pub write: Option<ChildStdin>,
        }
        
        impl Bot {
            fn new<S: AsRef<OsStr>>(program: S) -> io::Result<Self> {
                let mut proc = Command::new(program)
                    .stdin(Stdio::piped())
                    .stdout(Stdio::piped())
                    .spawn()?;
                let read = proc.stdout.take().map(|s| BufReader::new(s));
                let write = proc.stdin.take();
                Ok(Self { proc, read, write })
            }
        }
        
        #[derive(Parser, Debug)]
        #[command(author, version, about, long_about = None)]
        struct Args {
            bot_x: OsString,
            bot_o: OsString,
        }
        
        fn main() -> io::Result<()> {
            let args = Args::parse();
            println!("Player X: {:#?}", &args.bot_x);
            println!("Player O: {:#?}", &args.bot_o);
            let mut bots = [Bot::new(&args.bot_x)?, Bot::new(&args.bot_o)?];
            if let Some(s) = &mut bots[0].write {
                s.write(b"f\n")?;
            }
            if let Some(s) = &mut bots[1].write {
                s.write(b"s\n")?;
            }
            let mut game: Four<BinaryPlayer> = Four::new();
            let mut line = String::new();
            let mut stdout = io::stdout();
            let mut bot_read = bots
                .iter_mut()
                .map(|bot| bot.read.take().expect("no stdin"))
                .collect::<Vec<_>>();
            let mut bot_write = bots
                .iter_mut()
                .map(|bot| bot.write.take().expect("no stdout"))
                .collect::<Vec<_>>();
            'iter: for (from, to) in [(0, 1), (1, 0)].into_iter().cycle() {
                let from = &mut bot_read[from];
                let to = &mut bot_write[to];
                let pl = game.current_player();
                match 'read: {
                    line.clear();
                    print!("waiting for {}... ", pl);
                    stdout.flush()?;
                    if from.read_line(&mut line).is_err() {
                        println!("fail");
                        break 'read None;
                    }
                    println!("output: {:?}", &line);
                    to.write(&line.as_bytes())?;
                    to.flush()?;
                    match line.strip_suffix("\n").unwrap().parse::<u8>() {
                        Ok(m) => FourMove::try_from(m).ok(),
                        Err(_) => None,
                    }
                } {
                    Some(m) => {
                        let out = match game.apply(m) {
                            Some(out) => {
                                print!("{}: {}.{}", pl, m, &game);
                                out
                            }
                            None => {
                                println!("{}: invalid move ({}).", pl, m);
                                println!("{} wins.", pl.next());
                                break 'iter;
                            }
                        };
                        match out {
                            MoveOutcome::Win(p) => {
                                println!("{} wins.", p);
                                break 'iter;
                            }
                            MoveOutcome::Tie => {
                                println!("Tie.");
                                break 'iter;
                            }
                            MoveOutcome::Pass => {
                                println!("...");
                            }
                        }
                    }
                    None => {
                        println!("{} generated invalid output: {:?}", pl, &line);
                        println!("{} wins.", pl.next());
                        break 'iter;
                    }
                }
            }
            drop((bot_read, bot_write));
            let exits: Vec<_> = bots
                .into_iter()
                .map(|c| c.proc)
                .map(|mut c| c.wait())
                .collect();
            for e in exits {
                e?;
            }
            Ok(())
        }
        
        pl2.rs ASCII text
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        use crate::game::*;
        use std::fmt;
        
        #[derive(Copy, Clone, Eq, PartialEq, Debug)]
        pub enum BinaryPlayer {
            X,
            O,
        }
        
        impl fmt::Display for BinaryPlayer {
            fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str(match self {
                    Self::X => "X",
                    Self::O => "O",
                })
            }
        }
        
        impl GamePlayer for BinaryPlayer {
            fn first() -> Self {
                Self::X
            }
            fn next(&self) -> Self {
                match self {
                    Self::X => Self::O,
                    Self::O => Self::X,
                }
            }
        }
        
        .gitignore ASCII text
        1
        /target
        
        Cargo.lock ASCII text
          1
          2
          3
          4
          5
          6
          7
          8
          9
         10
         11
         12
         13
         14
         15
         16
         17
         18
         19
         20
         21
         22
         23
         24
         25
         26
         27
         28
         29
         30
         31
         32
         33
         34
         35
         36
         37
         38
         39
         40
         41
         42
         43
         44
         45
         46
         47
         48
         49
         50
         51
         52
         53
         54
         55
         56
         57
         58
         59
         60
         61
         62
         63
         64
         65
         66
         67
         68
         69
         70
         71
         72
         73
         74
         75
         76
         77
         78
         79
         80
         81
         82
         83
         84
         85
         86
         87
         88
         89
         90
         91
         92
         93
         94
         95
         96
         97
         98
         99
        100
        101
        102
        103
        104
        105
        106
        107
        108
        109
        110
        111
        112
        113
        114
        115
        116
        117
        118
        119
        120
        121
        122
        123
        124
        125
        126
        127
        128
        129
        130
        131
        132
        133
        134
        135
        136
        137
        138
        139
        140
        141
        142
        143
        144
        145
        146
        147
        148
        149
        150
        151
        152
        153
        154
        155
        156
        157
        158
        159
        160
        161
        162
        163
        164
        165
        166
        167
        168
        169
        170
        171
        172
        173
        174
        175
        176
        177
        178
        179
        180
        181
        182
        183
        184
        185
        186
        187
        188
        189
        190
        191
        192
        193
        194
        195
        196
        197
        198
        199
        200
        201
        202
        203
        204
        205
        206
        207
        208
        209
        210
        211
        212
        213
        214
        215
        216
        217
        218
        219
        220
        221
        222
        223
        224
        225
        226
        227
        228
        229
        230
        231
        232
        233
        234
        235
        236
        237
        238
        239
        240
        241
        242
        243
        244
        245
        246
        247
        248
        249
        250
        251
        252
        253
        254
        255
        256
        257
        258
        259
        260
        261
        262
        263
        264
        265
        266
        267
        268
        269
        270
        271
        272
        273
        274
        275
        276
        277
        278
        279
        280
        281
        282
        283
        284
        285
        286
        287
        288
        289
        290
        291
        292
        293
        294
        295
        296
        297
        298
        299
        300
        301
        302
        303
        304
        305
        306
        307
        308
        309
        310
        311
        312
        313
        314
        315
        316
        317
        318
        319
        320
        321
        322
        323
        324
        325
        326
        327
        328
        329
        330
        331
        332
        333
        334
        335
        336
        337
        338
        339
        340
        341
        342
        343
        344
        345
        346
        347
        348
        349
        350
        351
        352
        353
        354
        355
        356
        357
        358
        359
        360
        361
        362
        363
        364
        365
        366
        367
        368
        369
        370
        371
        372
        373
        374
        375
        376
        377
        378
        379
        380
        381
        382
        383
        384
        385
        386
        387
        388
        389
        390
        391
        392
        393
        394
        395
        396
        397
        398
        399
        400
        401
        402
        403
        404
        405
        406
        407
        408
        409
        410
        411
        412
        413
        414
        415
        416
        417
        418
        419
        420
        421
        422
        423
        424
        425
        426
        427
        428
        429
        430
        431
        432
        433
        434
        435
        436
        437
        438
        439
        440
        441
        442
        443
        444
        445
        446
        447
        448
        449
        450
        451
        452
        453
        454
        455
        456
        457
        458
        459
        460
        461
        462
        463
        464
        465
        466
        467
        468
        469
        470
        471
        472
        473
        474
        475
        476
        477
        478
        479
        480
        481
        482
        483
        484
        485
        486
        487
        488
        489
        490
        491
        492
        493
        494
        495
        496
        497
        498
        499
        500
        501
        502
        503
        504
        505
        506
        507
        508
        509
        510
        511
        512
        513
        514
        515
        516
        517
        518
        519
        520
        521
        522
        523
        524
        525
        526
        # This file is automatically @generated by Cargo.
        # It is not intended for manual editing.
        version = 3
        
        [[package]]
        name = "anstream"
        version = "0.6.4"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44"
        dependencies = [
         "anstyle",
         "anstyle-parse",
         "anstyle-query",
         "anstyle-wincon",
         "colorchoice",
         "utf8parse",
        ]
        
        [[package]]
        name = "anstyle"
        version = "1.0.4"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87"
        
        [[package]]
        name = "anstyle-parse"
        version = "0.2.2"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "317b9a89c1868f5ea6ff1d9539a69f45dffc21ce321ac1fd1160dfa48c8e2140"
        dependencies = [
         "utf8parse",
        ]
        
        [[package]]
        name = "anstyle-query"
        version = "1.0.0"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
        dependencies = [
         "windows-sys",
        ]
        
        [[package]]
        name = "anstyle-wincon"
        version = "3.0.1"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628"
        dependencies = [
         "anstyle",
         "windows-sys",
        ]
        
        [[package]]
        name = "autocfg"
        version = "1.1.0"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
        
        [[package]]
        name = "bitflags"
        version = "1.3.2"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
        
        [[package]]
        name = "bitflags"
        version = "2.4.0"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
        
        [[package]]
        name = "cfg-if"
        version = "1.0.0"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
        
        [[package]]
        name = "clap"
        version = "4.4.6"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "d04704f56c2cde07f43e8e2c154b43f216dc5c92fc98ada720177362f953b956"
        dependencies = [
         "clap_builder",
         "clap_derive",
        ]
        
        [[package]]
        name = "clap_builder"
        version = "4.4.6"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "0e231faeaca65ebd1ea3c737966bf858971cd38c3849107aa3ea7de90a804e45"
        dependencies = [
         "anstream",
         "anstyle",
         "clap_lex",
         "strsim",
        ]
        
        [[package]]
        name = "clap_derive"
        version = "4.4.2"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873"
        dependencies = [
         "heck",
         "proc-macro2",
         "quote",
         "syn",
        ]
        
        [[package]]
        name = "clap_lex"
        version = "0.5.1"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961"
        
        [[package]]
        name = "colorchoice"
        version = "1.0.0"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
        
        [[package]]
        name = "crossbeam-deque"
        version = "0.8.3"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef"
        dependencies = [
         "cfg-if",
         "crossbeam-epoch",
         "crossbeam-utils",
        ]
        
        [[package]]
        name = "crossbeam-epoch"
        version = "0.9.15"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7"
        dependencies = [
         "autocfg",
         "cfg-if",
         "crossbeam-utils",
         "memoffset",
         "scopeguard",
        ]
        
        [[package]]
        name = "crossbeam-utils"
        version = "0.8.16"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294"
        dependencies = [
         "cfg-if",
        ]
        
        [[package]]
        name = "crossterm"
        version = "0.27.0"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df"
        dependencies = [
         "bitflags 2.4.0",
         "crossterm_winapi",
         "libc",
         "mio",
         "parking_lot",
         "signal-hook",
         "signal-hook-mio",
         "winapi",
        ]
        
        [[package]]
        name = "crossterm_winapi"
        version = "0.9.1"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b"
        dependencies = [
         "winapi",
        ]
        
        [[package]]
        name = "either"
        version = "1.9.0"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
        
        [[package]]
        name = "getrandom"
        version = "0.2.10"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
        dependencies = [
         "cfg-if",
         "libc",
         "wasi",
        ]
        
        [[package]]
        name = "heck"
        version = "0.4.1"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
        
        [[package]]
        name = "libc"
        version = "0.2.149"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b"
        
        [[package]]
        name = "lock_api"
        version = "0.4.10"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16"
        dependencies = [
         "autocfg",
         "scopeguard",
        ]
        
        [[package]]
        name = "log"
        version = "0.4.20"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
        
        [[package]]
        name = "memoffset"
        version = "0.9.0"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c"
        dependencies = [
         "autocfg",
        ]
        
        [[package]]
        name = "mio"
        version = "0.8.8"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2"
        dependencies = [
         "libc",
         "log",
         "wasi",
         "windows-sys",
        ]
        
        [[package]]
        name = "parafour"
        version = "0.1.0"
        dependencies = [
         "clap",
         "crossterm",
         "rand",
         "rayon",
        ]
        
        [[package]]
        name = "parking_lot"
        version = "0.12.1"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
        dependencies = [
         "lock_api",
         "parking_lot_core",
        ]
        
        [[package]]
        name = "parking_lot_core"
        version = "0.9.8"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447"
        dependencies = [
         "cfg-if",
         "libc",
         "redox_syscall",
         "smallvec",
         "windows-targets",
        ]
        
        [[package]]
        name = "ppv-lite86"
        version = "0.2.17"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
        
        [[package]]
        name = "proc-macro2"
        version = "1.0.67"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328"
        dependencies = [
         "unicode-ident",
        ]
        
        [[package]]
        name = "quote"
        version = "1.0.33"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
        dependencies = [
         "proc-macro2",
        ]
        
        [[package]]
        name = "rand"
        version = "0.8.5"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
        dependencies = [
         "libc",
         "rand_chacha",
         "rand_core",
        ]
        
        [[package]]
        name = "rand_chacha"
        version = "0.3.1"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
        dependencies = [
         "ppv-lite86",
         "rand_core",
        ]
        
        [[package]]
        name = "rand_core"
        version = "0.6.4"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
        dependencies = [
         "getrandom",
        ]
        
        [[package]]
        name = "rayon"
        version = "1.8.0"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1"
        dependencies = [
         "either",
         "rayon-core",
        ]
        
        [[package]]
        name = "rayon-core"
        version = "1.12.0"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed"
        dependencies = [
         "crossbeam-deque",
         "crossbeam-utils",
        ]
        
        [[package]]
        name = "redox_syscall"
        version = "0.3.5"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
        dependencies = [
         "bitflags 1.3.2",
        ]
        
        [[package]]
        name = "scopeguard"
        version = "1.2.0"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
        
        [[package]]
        name = "signal-hook"
        version = "0.3.17"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801"
        dependencies = [
         "libc",
         "signal-hook-registry",
        ]
        
        [[package]]
        name = "signal-hook-mio"
        version = "0.2.3"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af"
        dependencies = [
         "libc",
         "mio",
         "signal-hook",
        ]
        
        [[package]]
        name = "signal-hook-registry"
        version = "1.4.1"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1"
        dependencies = [
         "libc",
        ]
        
        [[package]]
        name = "smallvec"
        version = "1.11.1"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a"
        
        [[package]]
        name = "strsim"
        version = "0.10.0"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
        
        [[package]]
        name = "syn"
        version = "2.0.36"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "91e02e55d62894af2a08aca894c6577281f76769ba47c94d5756bec8ac6e7373"
        dependencies = [
         "proc-macro2",
         "quote",
         "unicode-ident",
        ]
        
        [[package]]
        name = "unicode-ident"
        version = "1.0.12"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
        
        [[package]]
        name = "utf8parse"
        version = "0.2.1"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
        
        [[package]]
        name = "wasi"
        version = "0.11.0+wasi-snapshot-preview1"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
        
        [[package]]
        name = "winapi"
        version = "0.3.9"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
        dependencies = [
         "winapi-i686-pc-windows-gnu",
         "winapi-x86_64-pc-windows-gnu",
        ]
        
        [[package]]
        name = "winapi-i686-pc-windows-gnu"
        version = "0.4.0"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
        
        [[package]]
        name = "winapi-x86_64-pc-windows-gnu"
        version = "0.4.0"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
        
        [[package]]
        name = "windows-sys"
        version = "0.48.0"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
        dependencies = [
         "windows-targets",
        ]
        
        [[package]]
        name = "windows-targets"
        version = "0.48.5"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
        dependencies = [
         "windows_aarch64_gnullvm",
         "windows_aarch64_msvc",
         "windows_i686_gnu",
         "windows_i686_msvc",
         "windows_x86_64_gnu",
         "windows_x86_64_gnullvm",
         "windows_x86_64_msvc",
        ]
        
        [[package]]
        name = "windows_aarch64_gnullvm"
        version = "0.48.5"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
        
        [[package]]
        name = "windows_aarch64_msvc"
        version = "0.48.5"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
        
        [[package]]
        name = "windows_i686_gnu"
        version = "0.48.5"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
        
        [[package]]
        name = "windows_i686_msvc"
        version = "0.48.5"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
        
        [[package]]
        name = "windows_x86_64_gnu"
        version = "0.48.5"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
        
        [[package]]
        name = "windows_x86_64_gnullvm"
        version = "0.48.5"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
        
        [[package]]
        name = "windows_x86_64_msvc"
        version = "0.48.5"
        source = "registry+https://github.com/rust-lang/crates.io-index"
        checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
        
        Cargo.toml ASCII text
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        13
        14
        15
        [package]
        name = "parafour"
        description = "very Smart connect-four bot"
        version = "0.1.0"
        edition = "2021"
        
        [dependencies]
        clap = { version = "4.4.6", features = ["derive"] }
        crossterm = "0.27.0"
        rand = "0.8.5"
        rayon = "1.8.0"
        
        [[bin]]
        name = "pfdm"
        path = "src/pfdm.rs"
        

        entry #6

        written by yui
        submitted at
        0 likes

        guesses
        comments 0

        post a comment


        amogus.js ASCII text
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        13
        14
        // amogus
        
                    void((t,e)=>process.stdin.on       
               ("data",s=>{10==s[s.length-1]&&(e&&(e=>!
           t[e]||t[e].length>=6?                       
           process.exit(2):(t[e].push(1),(t=>t.length&&
           (t=>(process.stdout.write(t[1]+1+"\n"),t[0].
           push(727)))(t[~~(Math.random()*t.length)])||
           process.exit(1))(t.map((t,e)=>[t,e]).filter(
           t=>t[0].length<6))))(s[s.length-2]-49)||(102
           ==s[s.length-2]&&(e=>(process.stdout.write(e
               +1+"\n"),t[e].push(727)))(~~(Math.random
               ()*t.length)                ),e=1))}))([
               [],[],[],[],                [],[],[]],0)
        

        entry #7

        written by taswelll
        submitted at
        1 like

        guesses
        comments 0

        post a comment


        cg47.apls Unicode text, UTF-8 text
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
        44
        45
        46
        47
        48
        49
        50
        51
        52
        53
        54
        55
        56
        57
        58
        59
        60
        61
        62
        63
        64
        65
        66
        67
        68
        69
        70
        71
        72
        73
        74
        75
        76
        h w6 7
        gpgmh w0
        positions{h w  a b¯1+⍴  ,[2](1-⍳w-b)0 99(1-⍳h-a)0 99h w}
        gra⊃⍪/h wpositions¨(,1 41),(,⍨∘.=4)
        movecol{gp gm⋄(gpgm)((-⍴↑,1)@gm)}
        disp{'.⌺⎕'[1++]}
        inv(≠,⊂⊢)/
        threats{gp gm  h w0  gra⌿⍨~gra/⍤,2gpgm}
        rule{s ⍵⍵2 9999 2b⍺⍺/⋄(/s)∘⌿¨s b}
        
        claimeven{
            m2⌿⍤2(h÷2)w positions 1 11      ⍝ each possible position
            m⌿⍨~m/⍤,2                    ⍝ keep valid ones
        }rule(/⍤,(w h2|⍳h)∧∧)               ⍝ threats solved, (⊃⍴b)(⊃⍴⍺)≡⍴x
        baseinverse{(,∘.<w),[2]+99 22 99 1 3 2(∘.=w)∘.×1(2</,1)}rule(2=+/⍤,)
        vertical{
            m(¯1h2)2(¯1+h÷2)w positions 1 11
            m⌿⍨~m/⍤,2
        }rule(2=+/⍤,)
        aftereven{
            m((-h)2|⍳h-2)⍀⍤2(¯1+h÷2)w positions 1 41
            (⍀⍤<⊢)2m⌿⍨(∧⍱(/,)¯1<⊢)2m
        }rule(⊢≡())
        table 1
        table,1 1
        table,1 1 1
        table,1 1 1  3
        table,2 1 1 12  4
        table,2 1 1 12  4  4
        table,1 1 1  1 12 12 1
        table,1 1 1  3 23 12 1 3
        table,1 1 1  3 23 12 1 3 3
        table (⊢⌈⍉)table
        pairable{a b
             =1:/,ab
             =3:/a(/⍤⍲∨≡1)b
             =13:(pairable1pairable3)a b 
        }
        eval{h w0
            rules{( claimeven )( baseinverse )( vertical )( aftereven )}
            slvs sqrs typs(,(¨/))(threats rules)
            slvs sqrs typs(~/⍤,2sqrs)∘⌿¨slvs sqrs typs
            0=≢slvs:0
            conf~(∘.(table,)typs)pairable¨(⊂,)2 9999 2sqrs
            conf thing slvs
        }
        thing{¨   ⍝ ⍺:CONFlict(rules×rules) ⍵:SoLVeS(rules×threats)
            0=⊢/⍵:1          ⍝ no threats
            ~∨/m[;⊃⍋+]:0  ⍝ m: mask of rules that solve hardest threat
            r t~(m∘⌿)¨   ⍝ remove rules/threats solved by m 
            (r/)(r∘⌿)t/
        }
        oddthreat{
            tthreats inv (gp gm)
            ut⌿⍨3=t+/⍤,2gpgm
            ⍝ unsure why i need this, copied from somewhere else
            btm(-⍴↑⍪0)⊖∨⊖∨(2<0)2 threats 
            ⊖∨⊖∨btm<2(2<1gm)<2(w h2|⍳h)<2u>2gpgm
        }
        eval2{/,2⍵: {/,otoddthreat⍵:ot eval0} -eval}
        ab{a b
            0veval2 ⍵:v
            moves(movecol¨w)~⊂inv 
            /,2⍵:¯1 a{v a
                0=≢⍵:v
                b<uva b ab⍵:u
                u(ua) 1
            }moves
            1 b{v b
                0=≢⍵:v
                b<uva b ab⍵:u
                u(ub) 1
            }moves
        }
        
        {⊢?70}0
        

        entry #8

        written by luatic
        submitted at
        0 likes

        guesses
        comments 0

        post a comment


        bot.nim ASCII text
          1
          2
          3
          4
          5
          6
          7
          8
          9
         10
         11
         12
         13
         14
         15
         16
         17
         18
         19
         20
         21
         22
         23
         24
         25
         26
         27
         28
         29
         30
         31
         32
         33
         34
         35
         36
         37
         38
         39
         40
         41
         42
         43
         44
         45
         46
         47
         48
         49
         50
         51
         52
         53
         54
         55
         56
         57
         58
         59
         60
         61
         62
         63
         64
         65
         66
         67
         68
         69
         70
         71
         72
         73
         74
         75
         76
         77
         78
         79
         80
         81
         82
         83
         84
         85
         86
         87
         88
         89
         90
         91
         92
         93
         94
         95
         96
         97
         98
         99
        100
        101
        102
        103
        104
        105
        106
        107
        108
        109
        110
        111
        112
        113
        114
        115
        116
        117
        118
        119
        120
        121
        122
        123
        124
        125
        126
        127
        128
        129
        130
        131
        132
        133
        134
        135
        136
        137
        138
        139
        140
        141
        142
        143
        144
        145
        146
        147
        148
        149
        import std/bitops
        import std/strutils
        import std/options
        
        type
            X = range[0'u8..6'u8]
            Y = range[0'u8..5'u8]
            Stack = set[Y]
            Mask = array[X, Stack]
            Board = tuple[ours: Mask, theirs: Mask]
        
        type RowBitset = range[0'u8..127'u8]
        
        proc winRowUtil (row: RowBitset): bool =
            (row and 0b0001111) == 0b0001111 or
            (row and 0b0011110) == 0b0011110 or
            (row and 0b0111100) == 0b0111100 or
            (row and 0b1111000) == 0b1111000
        
        var winRows: set[RowBitset]
        for i in RowBitset(0)..127'u8:
            if winRowUtil(i):
                winRows.incl i
        
        proc winRow (row: RowBitset): bool =
            row in winRows
        
        proc row (m: Mask, y: Y): RowBitset =
            for x in X(0)..6:
                if y in m[x]:
                    result = result or (1'u8 shl x)
        
        proc ascDiag (m: Mask, x: X, y: Y): RowBitset =
            var j = 0'u8
            for i in -int8(x.min(y))..int8((6-x).min(5-y)):
                if Y(int8(y) + i) in m[X(int8(x) + i)]:
                    result = result or (1'u8 shl j)
                j += 1
        
        proc descDiag (m: Mask, x: X, y: Y): RowBitset =
            var j = 0'u8
            for i in -int8((6-x).min(y))..int8(x.min(5-y)):
                if Y(int8(y) + i) in m[X(int8(x) - i)]:
                    result = result or (1'u8 shl j)
                j += 1
        
        proc winMove (m: Mask, x: X, y: Y): bool =
            winRow(cast[RowBitset](m[x])) or
            winRow(m.row(y)) or
            winRow(m.descDiag(x, y)) or
            winRow(m.ascDiag(x, y))
        
        proc top (board: Board, x: X): Option[Y] =
            let used = cast[uint8](board.ours[x] + board.theirs[x])
            if used == 0:
                return Y(0).some
            let y = 8 - used.countLeadingZeroBits
            if y > 5:
                return Y.none
            return Y(y).some
        
        #[
        import std/unittest
        suite "bot":
            test "winRow":
                check(winRow 0b1111000)
                check(winRow 0b0111100)
                check(winRow 0b0011110)
                check(winRow 0b0001111)
                check(not winRow 0b0001101)
            let m: Mask = [
                {1, 2, 3},
                {0, 3},
                {1, 2},
                {0, 1},
                {0, 4},
                {3, 4, 5},
                {1, 2, 3},
            ]
            test "row":
                check(m.row(0) == 0b0011010)
                check(m.row(1) == 0b1001101)
            test "ascDiag":
                check(m.ascDiag(1, 1) == 0b110100)
            test "descDiag":
                check(m.descDiag(1, 1) == 0b100)
            test "winMove":
                let m: Mask = [{1, 2, 3, 4}, {}, {}, {}, {}, {}, {}]
                check(m.winMove(0, 4))
            test "top":
                check((ours: m, theirs: m).top(5) == none(Y))
                check((ours: m, theirs: m).top(1) == some(Y(4)))
        ]#
        
        proc applyMove (board: var Board, x: X, ours: bool) =
            let y = board.top(x).get
            if ours:
                board.ours[x].incl y
            else:
                board.theirs[x].incl y
        
        proc maximize (board: Board, depth: uint8): tuple[score: float, move: X] =
            if depth > 7:
                return
            result.score = -1
            var foundValidMove = false
            for x in X(0)..6:
                let top = board.top(x)
                if top.isNone:
                    continue
                let y = top.unsafeGet
                foundValidMove = true
                # Pick a valid move, even if it may seem futile.
                if result.score == -1:
                    result.move = x
                var ours = board.ours
                ours[x].incl y
                if ours.winMove(x, y):
                    return (score: 1, move: x)
                let min = -(ours: board.theirs, theirs: ours).maximize(depth + 1).score
                # Indirect win forcable?
                if min == 1:
                    return (score: 1, move: x)
                if min > result.score:
                    result.score = min
                    result.move = x
            # Returns an invalid move value (0) but meh
            if not foundValidMove:
                result.score = 0
                
        
        var board: Board
        
        proc makeMove () =
            let move = board.maximize(0).move
            board.applyMove(move, true)
            echo $(move + 1)
        
        let line = stdin.readLine
        if line == "f":
            makeMove()
        else:
            assert line == "s"
        
        while true:
            let move = stdin.readLine.parseUInt()
            assert move >= 1 and move <= 7
            board.applyMove(X(move - 1), false)
            makeMove()
        
        client.nim ASCII text
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
        44
        45
        46
        47
        48
        49
        50
        51
        52
        53
        54
        55
        56
        57
        58
        59
        60
        61
        62
        63
        64
        65
        66
        67
        68
        69
        70
        71
        72
        73
        74
        75
        76
        77
        78
        79
        80
        81
        82
        83
        84
        85
        86
        87
        88
        89
        90
        import os
        import osproc
        import std/strutils
        import std/streams
        
        type
            Spot = enum Free, Ours, Theirs
            Stack = array[6, Spot]
            Board = array[7, Stack]
        
        var board: Board
        var winner: Spot = Free
        
        proc printBoard =
            for row in countdown(5, 0):
                for col in 0..6:
                    const spotChar: array[Spot, char] = ['.', 'O', 'X']
                    stdout.write spotChar[board[col][row]]
                stdout.write '\n'
            stdout.flushFile()
        
        proc invalidMove (move: uint): bool =
            move < 1 or move > 7 or board[move - 1][^1] != Free
        
        proc inBounds (x, y: int): bool =
            x >= 0 and x < 7 and y >= 0 and y < 6
        
        proc countDir(x, y: uint, dx, dy: int): uint =
            var count: uint = 0
            var x = int(x)
            var y = int(y)
            let expected = board[x][y]
            while true:
                x += dx
                y += dy
                if not inBounds(x, y) or board[x][y] != expected:
                    break
                count += 1
            return count
        
        proc checkWinDir (x, y: uint, dx, dy: int): bool =
            return countDir(x, y, -dx, -dy) + 1 + countDir(x, y, dx, dy) >= 4
        
        proc checkWin (x, y: uint): bool =
            checkWinDir(x, y, 0, 1) or checkWinDir(x, y, 1, 0) or checkWinDir(x, y, 1, 1)
        
        var moves = 0
        proc makeMove (move: uint, player: Spot) =
            assert player != Free
            for y, spot in board[move]:
                if spot == Free:
                    board[move][y] = player
                    if checkWin(move, uint(y)):
                        winner = player
                    moves += 1
                    break
        
        var bot = startProcess(paramStr(1), options = {})
        var botIn = bot.inputStream
        var botOut = bot.outputStream
        proc sendCommand (command: string) =
            botIn.writeLine command
            botIn.flush
        sendCommand "s" # hoomans go first!
        
        while true:
            printBoard()
            if winner != Free or moves == 6*7:
                break
            block:
                echo "Make a move:"
                let move = stdin.readLine.parseUInt
                if invalidMove(move):
                    echo "Invalid move"
                    continue
                makeMove(move - 1, Ours)
                sendCommand $move
            if winner == Free:
                var line: string
                assert botOut.readLine line
                let move = line.parseUInt
                if invalidMove(move):
                    echo "Invalid move from bot"
                    break # can't resume with a broken bot
                makeMove(move - 1, Theirs)
        bot.terminate
        bot.close
        
        const outcome: array[Spot, string] = ["Draw", "You win!", "They win!"]
        echo outcome[winner]
        
        help.txt ASCII text
        1
        2
        Compile bot (or client): nim compile -d:release bot
        Use client: ./client bot
        

        entry #9

        written by vspf
        submitted at
        0 likes

        guesses
        comments 0

        post a comment


        theducksong.py ASCII text, with CRLF line terminators

        entry #10

        written by LyricLy
        submitted at
        0 likes

        guesses
        comments 0

        post a comment


        hair.py ASCII text
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
        44
        45
        46
        47
        48
        49
        50
        51
        52
        53
        54
        55
        56
        57
        58
        59
        60
        61
        62
        63
        64
        import time
        import random
        from multiprocessing.shared_memory import ShareableList
        
        
        def get_or_create(name):
            try:
                return ShareableList(name=name)
            except:
                return ShareableList(sequence=[0] + [b"-"*256]*256, name=name)
        
        def play_random_move(heights):
            o = random.choice([i for i, x in enumerate(heights, start=1) if x != 6])
            heights[o-1] += 1
            print(o)
        
        def play_randomly(go_first):
            """Boring agent used as a fallback when we can't find a partner (me irl)"""
            heights = [0]*7
            if go_first:
                play_random_move(heights)
            while True:
                i = int(input())
                heights[i-1] += 1
                play_random_move(heights)
        
        firsts = get_or_create("cg45_hair_firsts")
        seconds = get_or_create("cg45_hair_seconds")
        
        are_first = input() == "f"
        
        theirs, ours = (firsts, seconds) if are_first else (seconds, firsts)
        
        if not theirs[0]:
            channel = ShareableList([None])
            ours[1+ours[0]] = channel.shm.name
            ours[0] += 1
            for _ in range(10):
                time.sleep(0.5)
                if channel[0]:
                    break
            else:
                play_randomly(are_first)
            channel[0] = None
        else:
            theirs[0] -= 1
            channel = ShareableList(name=theirs[theirs[0]+1])
            channel[0] = 1
            while channel[0] is not None:
                pass
        
        def play_move():
            while channel[0] is None:
                pass
            print(channel[0])
            channel[0] = None
        
        if are_first:
            play_move()
        while True:
            channel[0] = int(input())
            while channel[0] is not None:
                pass
            play_move()
        

        entry #11

        written by JJRubes
        submitted at
        2 likes

        guesses
        comments 0

        post a comment


        dir jeu
        Case.java Unicode text, UTF-8 text
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        package jeu;
        
        public class Case {
        
            char nature;
        
            /**
             * Constructeur de Case
             *
             * @param nature_
             */
            Case (char nature_) {
                this.nature = nature_;
            }
        
            /**
             * get la nature d'une case
             *
             * @return nature de la case
             */
            public char getNature() {
                return this.nature;
            }
        
            /**
             * Permet de donner/changer la nature d'une case
             *
             * @param nat la nature à donner
             */
            public void setNature(char nat) {
                this.nature = nat;
            }
        }
        
        Conversion.java ASCII text
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
        44
        45
        46
        47
        48
        49
        50
        51
        52
        53
        54
        55
        56
        57
        58
        59
        60
        61
        62
        63
        64
        65
        66
        67
        68
        69
        70
        71
        72
        73
        74
        75
        76
        77
        package jeu;
        
        public class Conversion {
        
            /**
             * Retourne le char d'une case en String (ex: A10 --> A)
             *
             * @param caseEnString la case en String
             * @return x le char de la case
             */
            public char getCharFromString(String caseEnString){
                char x = ' ';
                if (caseEnString.length() == 2) {
                    x = caseEnString.charAt(0);
                } else if (caseEnString.length() == 3) {
                    x = caseEnString.charAt(0);
                }
                return x;
            }
        
            /**
             * Retourne l'entier d'une case en String (ex: A10 --> 10)
             *
             * @param caseEnString la case en String
             * @return y
             */
            public int getIntFromString(String caseEnString){
                int y = 0;
                if (caseEnString.length() == 2) {
                    y = Integer.parseInt(caseEnString.substring(1));
                } else if (caseEnString.length() == 3) {
                    y = Integer.parseInt(caseEnString.substring(1, 3));
                }
                return y;
            }
        
            public void formatCoupJoues(String coord1, String coord2, String nom, String nom2){
                String indent = "              "; // 20 spaces.
                int l;
        
                int add1 = nom.length()/2;
                int add2 = nom2.length()/2;
        
                if (nom.length() == 1){
                    nom = " " + nom + indent.charAt(0);
                    add1 = 1;
                } else if (nom.length() == 2){
                    nom += indent.charAt(0);
                }
        
                l = nom2.length();
                nom2 = " " + nom2;
                if (l == 1){
                    nom2 += " |";
                    add2 = 1;
                } else if (l == 2){
                    nom2 += indent.substring(0, 2) + "|";
                } else {
                    nom2 += " |";
                }
        
                l = coord1.length();
                coord1 = indent.substring(0, add1) + coord1 + indent.substring(0, add1);
                if(l == 2){
                    coord1 += " ";
                }
        
                l = coord2.length();
                coord2 = indent.substring(0, add2) + coord2 + indent.substring(0, add2);
                if (l == 2){
                    coord2 += " ";
                }
        
                System.out.println("| "+nom+" |"+nom2);
                System.out.println("|"+coord1+"|"+coord2+"|\n");
            }
        }
        
        IA.java Unicode text, UTF-8 text
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        package jeu;
        
        import java.util.ArrayList;
        import java.util.Random;
        
        public class IA {
        
            final String name;
            private final Random random = new Random();
        
            /**
             * Le constructeur de la classe IA
             *
             * @param name_ le nom de l'IA
             */
            IA(String name_) {
                this.name = name_;
            }
        
            /**
             * Renvoie le nom de l'IA
             *
             * @return le nom de l'IA
             */
            public String getName() {
                return this.name;
            }
        
            /**
             * Permet à l'IA de jouer un coup choisi au hasard choisi parmi les coups possibles
             *
             * @param coupsPossibles la liste des coups possibles
             * @return un coup choisi au hasard
             */
            public Case joueUnCoupRandom(ArrayList<Case> coupsPossibles) {
                return coupsPossibles.get(random.nextInt(coupsPossibles.size()));
            }
        }
        
        Joueur.java Unicode text, UTF-8 text
          1
          2
          3
          4
          5
          6
          7
          8
          9
         10
         11
         12
         13
         14
         15
         16
         17
         18
         19
         20
         21
         22
         23
         24
         25
         26
         27
         28
         29
         30
         31
         32
         33
         34
         35
         36
         37
         38
         39
         40
         41
         42
         43
         44
         45
         46
         47
         48
         49
         50
         51
         52
         53
         54
         55
         56
         57
         58
         59
         60
         61
         62
         63
         64
         65
         66
         67
         68
         69
         70
         71
         72
         73
         74
         75
         76
         77
         78
         79
         80
         81
         82
         83
         84
         85
         86
         87
         88
         89
         90
         91
         92
         93
         94
         95
         96
         97
         98
         99
        100
        package jeu;
        import java.util.ArrayList;
        import java.util.List;
        
        public class Joueur {
        
            String nomJoueur;
            int numJoueur;
            char natureJoueur;
            boolean isIA;
            List<String> coupJoues = new ArrayList<>();
        
            /**
             * Le constructeur de la classe Joueur
             *
             * @param nomJoueur le nom de joueur
             * @param nbJoueur le numéro du joueur
             * @param natureJoueur le symbole qu'utilisera le joueur
             * @param status est-ce que le joueur est une IA ou pas
             */
            Joueur(String nomJoueur, int nbJoueur, char natureJoueur, boolean status) {
                this.nomJoueur = nomJoueur;
                this.numJoueur = nbJoueur;
                this.natureJoueur = natureJoueur;
                this.isIA = status;
            }
        
            /**
             * Ajoute un coup aux coups joués du joueur
             *
             * @param coupJoue le coup joué
             */
            public void addCoupJoues(String coupJoue){
                this.coupJoues.add(coupJoue);
            }
        
            /**
             * Change le nom du joueur
             *
             * @param nomJoueur le nom à utiliser
             */
            public void setNomJoueur(String nomJoueur){
                this.nomJoueur = nomJoueur;
            }
        
            /**
             * Renvoie le nom du joueur
             *
             * @return le nom du joueur
             */
            public String getNomJoueur(){
                return this.nomJoueur;
            }
        
            /**
             * Change le numéro du joueur
             *
             * @param numJoueur le numéro à utiliser
             */
            public void setNumJoueur(int numJoueur){
                this.numJoueur = numJoueur;
            }
        
            /**
             * Renvoie le numéro du joueur
             *
             * @return le numéro du joueur
             */
            public int getNumJoueur(){
                return this.numJoueur;
            }
        
            /**
             * Renvoie la nature du joueur
             *
             * @return la nature du joueur
             */
            public char getNature() {
                return this.natureJoueur;
            }
        
            /**
             * Renvoie le statut du joueur
             *
             * @return le statut du joueur
             */
            public boolean getStatus() {
                return isIA;
            }
        
            /**
             * Change le statut du joueur
             *
             * @param status le statut à utiliser
             */
            public void setStatus(boolean status) {
                this.isIA = status;
            }
        
        }
        
        Main.java Unicode text, UTF-8 text
          1
          2
          3
          4
          5
          6
          7
          8
          9
         10
         11
         12
         13
         14
         15
         16
         17
         18
         19
         20
         21
         22
         23
         24
         25
         26
         27
         28
         29
         30
         31
         32
         33
         34
         35
         36
         37
         38
         39
         40
         41
         42
         43
         44
         45
         46
         47
         48
         49
         50
         51
         52
         53
         54
         55
         56
         57
         58
         59
         60
         61
         62
         63
         64
         65
         66
         67
         68
         69
         70
         71
         72
         73
         74
         75
         76
         77
         78
         79
         80
         81
         82
         83
         84
         85
         86
         87
         88
         89
         90
         91
         92
         93
         94
         95
         96
         97
         98
         99
        100
        101
        102
        103
        104
        105
        106
        107
        108
        109
        110
        111
        112
        113
        114
        115
        116
        117
        118
        119
        120
        121
        122
        123
        124
        125
        126
        127
        128
        129
        130
        131
        132
        133
        134
        135
        136
        137
        138
        139
        140
        141
        142
        143
        144
        145
        146
        147
        148
        149
        150
        151
        152
        153
        154
        155
        156
        157
        158
        159
        160
        161
        162
        163
        164
        165
        166
        167
        168
        169
        170
        171
        172
        173
        174
        175
        176
        177
        178
        179
        180
        181
        182
        183
        184
        185
        186
        187
        188
        189
        190
        191
        192
        193
        194
        195
        196
        197
        198
        199
        200
        201
        202
        203
        204
        205
        206
        207
        208
        209
        210
        211
        212
        213
        214
        package jeu;
        
        import java.util.ArrayList;
        import java.util.Scanner;
        
        public class Main {
        
            static private final Scanner in = new Scanner(System.in);
            static private char x;
            static private int y;
            static private boolean boot = true;
            static private char nature = 'X';
            static private Joueur jH = new Joueur("Joueur1", 0, 'X', false);
            static private Joueur j2;
            static private IA playerIA = new IA("IA");
            static private int playersTurn = 1;
        
            /**
             * La fonction Main du programme
             * 
             * @param args
             */
            public static void main(String[] args) {
                UI m = new UI();
                Screen s = new Screen(bootMain()); // max 26 because the alphabet is 26 char long :)
        
                s.clear();
                s.display(0);
        
                System.out.println("* Menu *");
                while (true) {
                    String input = "";
                    if (playersTurn == 1) {
                        input = m.userInterface(jH.nomJoueur, jH.coupJoues, s);
                    } else if (playersTurn == 2){
                        if (j2.isIA) {
                            input = Screen.getStringFromCase(playerIA.joueUnCoupRandom(s.getAllPossiblePlays(false)));
                        } else {
                            input = m.userInterface(j2.nomJoueur, j2.coupJoues, s);
                        }
                    }
        
                    try {
                        if (input.length() == 2) {  //Formate l'entrée utlisateur en Char et int
                            x = input.charAt(0);
                            y = Integer.parseInt(input.substring(1));
                        } else if (input.length() == 3) {
                            x = input.charAt(0);
                            y = Integer.parseInt(input.substring(1, 3));
                        }
                    } catch (Exception e){
                        System.out.println("La valeur entrée n'est pas valable");
                    }
        
        
                    if (s.checkUserInput(x, y)) {
                        if (playersTurn == 1) {
                            jH.addCoupJoues(input);
                            nature = jH.natureJoueur;
                            playersTurn++;
                        } else if (playersTurn == 2) {
                            if (j2.isIA) {
                                System.out.println("L'IA joue : " + input);
                            }
                            j2.addCoupJoues(input);
                            nature = j2.natureJoueur;
                            playersTurn--;
                        }
        
                        s.setPoint(x, y, nature);
                        s.display(0);
                        s.getAllPlayedCase();
                    }
                    s.checkIfWin();
                }
            }
        
            /**
             * Est utilisé une fois au demarage de chaque partie pour choisir la taille du plateau et le nombre de joueurs
             *
             * @return 0
             */
            public static int bootMain() {
                UI m = new UI();
                if (boot) {
                    boot = false;
                    intro();
                    return (m.taillePlateau());
                }
                return 0;
            }
        
            /**
             * Supprime tout les coups joués par les joueurs
             */
            public void clearCoupJoues(){
                jH.coupJoues.clear();
                j2.coupJoues.clear();
            }
        
            /**
             * Introduction + Choix de l'adversaire et des noms
             */
            public static void intro() {
                UI m = new UI();
                String adversaire;
                boolean boucle = true;
        
                    System.out.println("\n\n");
                    System.out.println("                ** Bienvenue au jeu du Gomoku ** \n"+
                                        "-Pour gagner il faut aligner 5 pions dans n'importe quel direction\n"+
                                        "-Si jamais vous êtes bloqué(e) vous pouvez utiliser la commande /aide \n\n"+
                                        "Aller, c'est parti !\n\n"+
                                        "Voulez-vous jouer contre l'ordinateur(O) ou contre un humain(H) ? ");
                while (boucle) {
                    adversaire = in.nextLine().trim();
                    try {
                        char choixAdversaire = adversaire.charAt(0);
                        if (choixAdversaire == 'H' || choixAdversaire == 'h') {
                            j2 = new Joueur("Joueur2", 1, 'O', false);
                            jH.nomJoueur = m.choixNomJoueur(1);
                            j2.nomJoueur = m.choixNomJoueur(2);
                            boucle = false;
                        } else if (choixAdversaire == 'O' || choixAdversaire == 'o') {
                            j2 = new Joueur(playerIA.getName(), 1, 'O', true);
                            jH.nomJoueur = m.choixNomJoueur(1);
                            j2.nomJoueur = j2.getNomJoueur();
                            boucle = false;
                        } else {
                            System.out.println("erreur: la valeur entrée n'est pas valable");
                        }
                    } catch (Exception e) {
                        System.out.println("erreur: la valeur entrée n'est pas valable");
                        //System.out.println("erreur: la valeur entrée n'est pas valable "+e);
                    }
                }
            }
        
            public String getJoueurFromChar(char symbole) {
                if (symbole == jH.getNature()) {
                    return jH.getNomJoueur();
                } else {
                    return j2.getNomJoueur();
                }
            }
        
            /**
             * Affiche tout les coups joués de chaques joueurs à la fin
             */
            public void afficherToutLesCoupsJoues(){
                System.out.println("Tout les coups joués dans cette partie : ");
        
                ArrayList<String> coupJoues = new ArrayList<>();
                String nom = jH.nomJoueur;
                String nom2 = j2.nomJoueur;
                String indent = "              "; // 20 spaces.
                int l;
                int add1 = nom.length()/2;
                int add2 = nom2.length()/2;
        
                if (nom.length() == 1){
                    nom = " " + nom + indent.charAt(0);
                    add1 = 1;
                } else if (nom.length() == 2){
                    nom += indent.charAt(0);
                }
        
                l = nom2.length();
                nom2 = " " + nom2;
                if (l == 1){
                    nom2 += " |";
                    add2 = 1;
                } else if (l == 2){
                    nom2 += indent.substring(0, 2) + "|";
                } else {
                    nom2 += " |";
                }
                System.out.println("| "+nom+" |"+nom2);
        
                coupJoues.addAll(jH.coupJoues);
                coupJoues.addAll(j2.coupJoues);
        
                for (int p1 = 0, p2 = (jH.coupJoues).size(); p1 < (jH.coupJoues).size() || p2 < (jH.coupJoues).size()+(j2.coupJoues).size(); p1++, p2++) {
        
                    String coord1 = "";
                    String coord2 = "";
        
                    if (p2 == (jH.coupJoues).size()+(j2.coupJoues).size()) {
                        coord1 = coupJoues.get(p1);
                    }
                    else if(p1 == (jH.coupJoues).size()) {
                        coord2 = coupJoues.get(p2);
                    }
                    else {
                        coord1 = coupJoues.get(p1);
                        coord2 = coupJoues.get(p2);
                    }
        
                    l = coord1.length();
                    coord1 = indent.substring(0, add1) + coord1 + indent.substring(0, add1);
                    if(l == 2) coord1 += " ";
        
                    l = coord2.length();
                    coord2 = indent.substring(0, add2) + coord2 + indent.substring(0, add2);
                    if (l == 2) coord2 += " ";
        
        
                    if (p2 == (jH.coupJoues).size()+(j2.coupJoues).size()) System.out.println("|"+coord1+"| "+indent.substring(0,(j2.nomJoueur).length()+1)+" |");
                    else if(p1 == (jH.coupJoues).size()) System.out.println("| "+indent.substring(0,(jH.nomJoueur).length())+" |"+coord2+"|");
                    else System.out.println("|"+coord1+"|"+coord2+"|");
        
                }
            }
        }
        
        Screen.java Unicode text, UTF-8 text
          1
          2
          3
          4
          5
          6
          7
          8
          9
         10
         11
         12
         13
         14
         15
         16
         17
         18
         19
         20
         21
         22
         23
         24
         25
         26
         27
         28
         29
         30
         31
         32
         33
         34
         35
         36
         37
         38
         39
         40
         41
         42
         43
         44
         45
         46
         47
         48
         49
         50
         51
         52
         53
         54
         55
         56
         57
         58
         59
         60
         61
         62
         63
         64
         65
         66
         67
         68
         69
         70
         71
         72
         73
         74
         75
         76
         77
         78
         79
         80
         81
         82
         83
         84
         85
         86
         87
         88
         89
         90
         91
         92
         93
         94
         95
         96
         97
         98
         99
        100
        101
        102
        103
        104
        105
        106
        107
        108
        109
        110
        111
        112
        113
        114
        115
        116
        117
        118
        119
        120
        121
        122
        123
        124
        125
        126
        127
        128
        129
        130
        131
        132
        133
        134
        135
        136
        137
        138
        139
        140
        141
        142
        143
        144
        145
        146
        147
        148
        149
        150
        151
        152
        153
        154
        155
        156
        157
        158
        159
        160
        161
        162
        163
        164
        165
        166
        167
        168
        169
        170
        171
        172
        173
        174
        175
        176
        177
        178
        179
        180
        181
        182
        183
        184
        185
        186
        187
        188
        189
        190
        191
        192
        193
        194
        195
        196
        197
        198
        199
        200
        201
        202
        203
        204
        205
        206
        207
        208
        209
        210
        211
        212
        213
        214
        215
        216
        217
        218
        219
        220
        221
        222
        223
        224
        225
        226
        227
        228
        229
        230
        231
        232
        233
        234
        235
        236
        237
        238
        239
        240
        241
        242
        243
        244
        245
        246
        247
        248
        249
        250
        251
        252
        253
        254
        255
        256
        257
        258
        259
        260
        261
        262
        263
        264
        265
        266
        267
        268
        269
        270
        271
        272
        273
        274
        275
        276
        277
        278
        279
        280
        281
        282
        283
        284
        285
        286
        287
        288
        289
        290
        291
        292
        293
        294
        295
        296
        297
        298
        299
        300
        301
        302
        303
        304
        305
        306
        307
        308
        309
        310
        311
        312
        313
        314
        315
        316
        317
        318
        319
        320
        321
        322
        323
        324
        325
        326
        327
        328
        329
        330
        331
        332
        333
        334
        335
        336
        337
        338
        339
        340
        341
        342
        343
        344
        345
        346
        347
        348
        349
        350
        351
        352
        353
        354
        355
        356
        357
        358
        359
        360
        361
        362
        363
        364
        365
        366
        367
        368
        369
        370
        371
        372
        373
        374
        375
        376
        377
        378
        379
        380
        381
        382
        383
        384
        385
        386
        387
        388
        389
        390
        391
        392
        393
        394
        395
        396
        397
        398
        399
        400
        401
        402
        403
        404
        405
        406
        407
        408
        409
        410
        411
        412
        413
        414
        415
        416
        417
        418
        419
        420
        421
        422
        423
        424
        425
        426
        427
        428
        429
        430
        431
        432
        433
        434
        435
        436
        437
        438
        439
        440
        441
        442
        443
        444
        445
        446
        447
        448
        449
        450
        451
        452
        453
        454
        455
        456
        457
        458
        459
        460
        461
        462
        463
        464
        465
        466
        467
        468
        469
        470
        471
        472
        473
        474
        475
        476
        477
        478
        479
        480
        481
        482
        483
        484
        485
        486
        487
        488
        489
        490
        491
        492
        493
        494
        495
        496
        497
        498
        499
        500
        501
        502
        503
        504
        505
        506
        507
        508
        509
        510
        511
        512
        513
        514
        515
        516
        package jeu;
        
        import java.util.ArrayList;
        import java.util.Scanner;
        
        public class Screen {
        
            private Main m = new Main();
            private Conversion c = new Conversion();
            static private Scanner in = new Scanner(System.in);
        
            private final int size;
            private static Case[][] image;
        
            private boolean win = false;
        
            private final static char[] alphabet = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
                    'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' };
                    
            String[] direction = {
                "NORD-OUEST",
                "NORD",
                "NORD-EST",
                "EST", 
                "SUD-EST",
                "SUD",
                "SUD-OUEST",
                "OUEST"
            };
        
        
            /**
             * Constructeur de la classe Screen
             * 
             * @param size_ la taille voulue par l'utilisateur
             */
            Screen(int size_) {
                size = size_;
                image = new Case[size * 2][size];
            }
        
            /**
             * Renvoie l'image de l'objet screen en question
             * 
             * @return l'image
             */
            public Case[][] getImage() {
                return image;
            }
        
            /**
             * Verifie si la valeur entrée par l'utilisateur est valable
             * 
             * @param letter la partie 'lettre' de l'entrée
             * @param chiffre la partie 'chiffre/nombre' de l'entrée
             * @return true si la valeur est valable
             */
            public boolean checkUserInput(char letter, int chiffre) {
                String play = letter + String.valueOf(chiffre);
                int value = new String(alphabet).indexOf(letter);
        
                if (value != -1 && 0 < chiffre && chiffre <= size) {
                    ArrayList<String> possiblesMovesString;
                    possiblesMovesString = getStringListFromCaseList(getAllPossiblePlays(false));
        
                    if (possiblesMovesString.contains(play)) {
                        // System.out.println("Possible");
                        return true;
                    } else {
                        System.out.println("Le coup " + play + " n'est pas jouable");
                        return false;
                    }
                }
                System.out.println("Le coup " + play + " n'est pas valable");
                return false;
            }
        
        
            public boolean checkIfCasePossible(char letter, int chiffre) {
                String play = letter + String.valueOf(chiffre);
                int value = new String(alphabet).indexOf(letter);
        
                if (value != -1 && 0 < chiffre && chiffre <= size) {
                    ArrayList<String> possiblesMovesString;
                    possiblesMovesString = getStringListFromCaseList(getAllPossiblePlays(false));
        
                    if (possiblesMovesString.contains(play)) {
                        // System.out.println("Possible");
                        return true;
                    } else {
                        possiblesMovesString = getStringListFromCaseList(getAllPlayedCase());
                        return possiblesMovesString.contains(play);
                    }
                }
                return false;
            }
        
            /**
             * Converti une list de Case en list de Strings
             *
             * @param possibleMoves liste de case des coups possibles
             * @return possiblesMovesString liste de Strings des coups possibles
             */
            public ArrayList<String> caseListToStringList(ArrayList<Case> possibleMoves) {
                ArrayList<String> possiblesMovesString = new ArrayList<>();
                for (Case case1 : possibleMoves) {
                    possiblesMovesString.add(getStringFromCase(case1));
                }
                return possiblesMovesString;
            }
        
            /**
             * donne la position d'une lettre dans l'alphabet
             * @param letter    la lettre a chercher dans l'alphabet
             * @return la position d'une lettre dans l'alphabet - 1
             */
            public int getPositionOfLetter(char letter){
                return(new String(alphabet).indexOf(letter));
            }
        
            /**
             * Place un pion sur le plateau avec sa nature
             * 
             * @param letter la coordonnées 'lettre' du pion
             * @param chiffre la coordonées 'chiffre/nombre' du pion
             * @param nature sa nature
             */
            public void setPoint(char letter, int chiffre, char nature) {
                int x = getPositionOfLetter(letter);
                if (x == 0) {
                    x++;
                } else if (x == 1) {
                    x = x + 2;
                } else {
                    x = x * 2 + 1;
                }
                image[x][chiffre - 1].setNature(nature);
            }
        
            /**
             * Supprime tout les pions sur le terrain
             */
            public void clear() {
                for (int r = 0; r < size; r++) {
                    for (int c = 0; c < size * 2; c++) {
                        image[c][r] = new Case(' ');
                    }
                }
            }
        
            /**
             * Affiche le terrain avec les pions joués
             *
             * @param command permet d'ajouter des options lors de l'affichage
             */
            public void display(int command) {
                int i = 0;
        
                ArrayList<String> possiblesMovesString;
                possiblesMovesString = getStringListFromCaseList(getAllPossiblePlays(false));
        
                ArrayList<String> texte = new ArrayList<>();
                texte.add("/aide        : affiche l'aide");
                texte.add("/joues       : affiche les coups joués par joueur");
                texte.add("/plateau     : affiche le plateau");
                texte.add("/redemarrer  : redemarre la partie");
                texte.add("/quit        : stop la partie");
        
                for (String string : possiblesMovesString) {
                    setPoint(c.getCharFromString(string), c.getIntFromString(string), '-');
                }
                
                displayLetters();
                displayBar();
        
                for (int r = 0; r < size; r++) {
                    String lineNum = Integer.toString(r + 1);
                    if (r < 9) {
                        lineNum = (" " + (r + 1));
                    }
                    System.out.print(lineNum + "|");
                    for (int c = 0; c < size * 2; c++) {
                        System.out.print(image[c][r].nature);
                    }
        
                    if (command == 1) {
                        if (i != 4) {
                            System.out.println(" |      " + texte.get(r));
                            i++;
                        } else {
                            System.out.println(" |");
                        }
                    } else {
                        System.out.println(" |");
                    }
                }
        
                for (String string : possiblesMovesString) {
                    setPoint(c.getCharFromString(string), c.getIntFromString(string), ' ');
                }
                displayBar();
            }
        
            /**
             * Dessine la barre supérieure et inférieur (ex: +-------------------+)
             */
            private void displayBar() {
                System.out.print("  +");
                for (int c = 0; c < size * 2; c++) {
                    System.out.print("-");
                }
                System.out.println("-+");
            }
        
            /**
             * Dessine les lettres des colonnes
             */
            private void displayLetters() {
                System.out.print("   ");
                for (int i = 0; i < size; i++) {
                    System.out.print(" " + alphabet[i]);
                }
                System.out.println();
            }
        
            /**
             * Retourne un String de position (ex: A5) en partant de coordonées dans le tableau de case
             * 
             * @param x la coordonée en x
             * @param y la coordonée en y
             * @return la position de la Case
             */
            static public String getStringFromInt(int x, int y) {
                return alphabet[x / 2] + String.valueOf(y + 1);
            }
        
            /**
             * Renvoie la case correspondant à la position (ex: A5) donnée
             *
             * @param string_ la position donnée
             * @return la Case correspondante
             */
            public static Case getCaseFromString(String string_) {
                char letter = string_.charAt(0);
                int indexOfLetter = (new String(alphabet).indexOf(letter)) *2 +1;
                int number = Integer.parseInt(String.valueOf(string_.charAt(1)))-1;
                //System.out.println("index of letter '" + letter + "'  = "+indexOfLetter+"    NUMBER ="+number+"    CASE DANS METHODE == "+image[indexOfLetter][number].getNature());
                try {
                    return image[indexOfLetter][number];
                } catch (Exception e){
                    //System.out.println("erreur : getCaseFromString : "+e);
                }
                return image[indexOfLetter][number-1];
            }
        
            /**
             * Renvoie la position (ex: A5) correspondant à une Case donnée
             *
             * @param case_ la Case donnée
             * @return la position de la Case correspondante
             */
            public static String getStringFromCase(Case case_) {
                String letter = "";
                String nb = "";
                for (int i = 0; i < image.length; i++) {
                    for (int j = 0; j < image[i].length; j++) {
                        if (image[i][j] == case_) {
                            letter = Character.toString(alphabet[i / 2]);
                            nb = String.valueOf(j + 1);
                        }
                    }
                }
                return letter.concat(nb);
            }
        
            /**
             * Renvoie les positions (ex: A5) correspondantes à plusieurs Cases données
             * 
             * @param caseList les Cases données
             * @return les positions des Cases correspondantes
             */
            public ArrayList<String> getStringListFromCaseList(ArrayList<Case> caseList) {
                ArrayList<String> possiblesMovesString = new ArrayList<>();
                for (Case currentCase : caseList) {
                    possiblesMovesString.add(getStringFromCase(currentCase));
                }
                return possiblesMovesString;
            }
        
            /**
             * Retourne le nombre de coups joués jusqu'ici dans la partie
             *
             * @return le nombre de coups joués
             */
            public int getNbCoupsJoues() {
                int nb = 0;
                for (Case[] cases : image) {
                    for (Case aCase : cases) {
                        if (aCase.getNature() != ' ') {
                            nb++;
                        }
                    }
                }
                if (nb == size*size){
                    System.out.println("Tout les coups possibles ont était joués, la partie est terminée !");
                    restart();
                    return 0;
                }
                return nb;
            }
        
            /**
             * Retourne une liste des coups jouable actuellement dans la partie
             * 
             * @param afficher option permettant d'afficher ou pas la liste sous forme textuelle des coups jouables
             * @return la liste de Cases jouables
             */
            public ArrayList<Case> getAllPossiblePlays(boolean afficher) {
                ArrayList<Case> possibleMoves = new ArrayList<>();
                ArrayList<Case> adjacentCases = new ArrayList<>();
                int nbCoupsJoues = getNbCoupsJoues();
        
                possibleMoves.clear();
        
                // If there's at least one move already played
                if (nbCoupsJoues >= 1) {
        
                    // Check every cases
                    for (int i = 0; i < image.length; i++) {
                        for (int j = 0; j < image[i].length; j++) {
        
                            // If it finds a non empty case
                            if (image[i][j].getNature() != ' ') {
                                nbCoupsJoues++;
                                adjacentCases.clear();
        
                                // Check all around the case to see if there's another case
                                for (int a = -2; a <= 2; a = a + 2) {
                                    for (int b = -1; b <= 1; b++) {
                                        // If a case exists, add it
                                        try {
                                            if (image[i + a][j + b] != null && image[i + a][j + b] != image[i][j] && image[i + a][j + b].nature == ' ') {
                                                adjacentCases.add(image[i + a][j + b]);
                                            }
                                        } catch (Exception e) {
                                            // System.out.println("Erreur: " + e);
                                        }
                                    }
                                }
                                // Then, for each non empty case, add the adjacent cases to the list of possible
                                // moves
                                possibleMoves.addAll(adjacentCases);
                            }
                        }
                    }
        
                // Else (if there are no move already played)
                } else {
                    // Add all cases
                    for (int i = 0; i < image.length; i = i + 2) {
                        for (int j = 0; j < image[i].length; j++) {
                            possibleMoves.add(image[i][j]);
                        }
                    }
                }
                if (possibleMoves.size() == image.length * image.length) {
                    System.out.println("Play anywhere");
        
                } else if (afficher) {
                    System.out.println("You can play at : ");
                    for (Case c : possibleMoves) {
                        System.out.println(getStringFromCase(c));
                    }
                }
                return possibleMoves;
            }
        
            /**
             * Permet de se déplacer dans le tableau en suivant une direction
             *
             * @param current la Case de départ
             * @param dir_ la direction à suivre
             * @return la position de la Case d'arrivée
             */
            public String moveWithDir(Case current, String dir_) {
        
                int coX = 0;
                int coY = 0;
        
                for (int i = 1; i < image.length; i = i + 2) {
                    for (int j = 0; j < image[i].length; j++) {
                        if (image[i][j] == current) {
                            coX = i;
                            coY = j;
                        }
                    }
                }
        
                switch (dir_) {
                    case "NORD-OUEST":
                        coX=coX-2;
                        coY--;
                        break;
                    case "NORD-EST":
                        coX=coX+2;
                        coY--;
                        break;
                    case "SUD-OUEST":
                        coX=coX-2;
                        coY++;
                        break;
                    case "SUD-EST":
                        coX=coX+2;
                        coY++;
                        break;
                    case "NORD":
                        coY--;
                        break;
                    case "SUD":
                        coY++;
                        break;
                    case "OUEST":
                        coX=coX-2;
                        break;
                    case "EST":
                        coX=coX+2;
                        break;
                }
                if (coY >= 0 && coY <= image.length && coX > 0 && coX < image.length) {
                    return getStringFromInt(coX, coY);
                } else {
                    return "er";
                }
            }
        
            /**
             * Renvoie toutes les cases où un coup a été joué
             *
             * @return une liste de toutes les cases jouées
             */
            public ArrayList<Case> getAllPlayedCase() {
                ArrayList<Case> allPlayed = new ArrayList<>();
        
                for (int i = 1; i < image.length; i = i + 2) {
                    for (int j = 0; j < image[i].length; j++) {
                        if (image[i][j].getNature() != ' ') {
                            allPlayed.add(image[i][j]);
                        }
                    }
                }
                return allPlayed;
            }
        
            /**
             * Vérifie si en partant d'une case et en suivant une direction, on obtient une condition de victoire
             *
             * @param current la case actuelle
             * @param dir la direction de vérification
             * @param nb le nombre de cases similaires déjà rencontrées
             */
            public void checkIfWinFromCase(Case current, String dir, int nb) {
                char symbole = current.nature;
                String afterMoving = moveWithDir(current, dir);
                if (!afterMoving.equals("er")) { //si il n'y a pas d'erreur on continue dans le if
        
                    if (getCaseFromString(afterMoving) != null) {
                        Case newCase = getCaseFromString(afterMoving);
        
                        if (newCase.nature == symbole && checkIfCasePossible(c.getCharFromString(afterMoving),c.getIntFromString(afterMoving))) {
                            nb++;
                            if (nb == 5 && newCase.nature == symbole) {
                                win = true;
                            } else {
                                checkIfWinFromCase(newCase, dir, nb);
                            }
                        }
                    }
                }
            }
        
            /**
             * Vérifie si le plateau actuel présente une victoire pour un joueur
             */
            public void checkIfWin() {
        
                ArrayList<Case> allPlayed = getAllPlayedCase();
        
                allPlayed.forEach(current -> {
                    for (String dir_ : direction) {
                        checkIfWinFromCase(current, dir_, 1);
                        if (win) {
                            System.out.println("Bravo "+m.getJoueurFromChar(current.nature)+" vous avez gagné(e) !! \n");
                            m.afficherToutLesCoupsJoues();
                            restart();
                            win=false;
                        }
                    }
                });
            }
        
            /**
             * Permets de redémarrer (ou non) une partie
             */
            public void restart(){
                System.out.println("\nVoulez-vous rejouer ? O/N");
                String commande = in.nextLine().trim();
                if (commande.equals("O") || commande.equals("o") || commande.equals("oui") || commande.equals("Oui")){
                    clear();
                    m.clearCoupJoues();
                    System.out.println("\nAller c'est reparti !\n");
                } else {
                    System.out.println("Merci d'avoir joué au gomoku fait par Roméo Tesei et Fil Veith,\nBonne Journée et à bientôt,");
                    System.exit(0);
                }
            }
        }
        
        UI.java Unicode text, UTF-8 text
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
        44
        45
        46
        47
        48
        49
        50
        51
        52
        53
        54
        55
        56
        57
        58
        59
        60
        61
        62
        63
        64
        65
        66
        67
        68
        69
        70
        71
        72
        73
        74
        75
        76
        77
        78
        79
        80
        81
        82
        83
        84
        85
        86
        87
        88
        89
        90
        91
        92
        93
        94
        95
        96
        97
        98
        99
        package jeu;
        
        import java.io.PrintStream;
        import java.util.List;
        import java.util.Scanner;
        
        public class UI {
        
            static private Scanner in = new Scanner(System.in);
            static private PrintStream out = System.out;
        
            /**
             * Choix de la taille du plateau
             * 
             * @return la taille du plateau
             */
            public int taillePlateau() {
                int taillePlateauInt = 10;
                out.println("Quel taille de plateau voulez-vous ? (entre 5 et 26)");    //si aucune valeur de l'utilisateur alors taille = 10
                while (true) {
                    String taillePlateau = in.nextLine().trim();
                    try {
                        taillePlateauInt = Integer.parseInt(taillePlateau);
                    } catch (Exception e) {
                        out.println("erreur: la valeur entrée n'est pas valable ");
                    }
        
                    if (taillePlateauInt <= 26 && taillePlateauInt >= 5) {
                        return taillePlateauInt;
                    }
                    out.println("erreur: la valeur entrée n'est pas valable ");
                }
            }
        
            /**
             * Choix du nom du joueur
             * 
             * @param nbJoueur le numéro du joueur (1 ou 2)
             * @return le nom de joueur
             */
            public String choixNomJoueur(int nbJoueur) {
                out.println("Nom du joueur " + nbJoueur + " : ");
                String nomJoueur = in.nextLine().trim();
                if (nomJoueur.equals(""))
                    nomJoueur = "Joueur" + nbJoueur;
                return nomJoueur;
            }
        
            /**
             * Methode permettant d'afficher le necessaire au(x) joueur(s)
             *
             * @param nomJoueur le nom du joueur actuel
             * @param coupJoues la liste des coups joués par le joueur actuel
             * @param screen_ le screen actuel
             * @return l'interaction avec le joueur
             */
            public String userInterface(String nomJoueur, List<String> coupJoues, Screen screen_) {
                Main m = new Main();
                boolean boucler = true;
                while (boucler) {
                    out.println("Où voulez vous jouer " + nomJoueur + " ? ");
                    String commande = in.nextLine().trim();
                    out.println("\n\n");
                    switch (commande) {
                    case "/quit":
                        out.println("-> Bye.");
                        boucler = false;
                        System.exit(0);
                    case "/aide":
                        screen_.display(1);
                        break;
                    case "/plateau":
                        screen_.display(0);
                        break;
                    case "/coup":
                        screen_.getAllPossiblePlays(true);
                        break;
                    case "/redemarrer":
                        screen_.clear();
                        m.clearCoupJoues();
                        screen_.display(0);
                        break;
                    case "/joues":
                        for (String cJ : coupJoues) {
                            out.println("" + cJ);
                        }
                        out.println();
                        break;
                    default:
                        if (commande.length() == 2 || commande.length() == 3) {
                            return commande;
                        }
                        out.println("-> commande inconnue '" + commande + "'");
                        break;
                    }
                }
                return "";
            }
        }
        
        makefile Unicode text, UTF-8 text
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        L := $(wildcard ../*/*.lua)
        P := $(wildcard ../*/*.py)
        run:
        ifdef L
        	@lua $L
        else ifdef P
        	@python3 $P
        else
        	@echo Merde, il n\'y a pas d\'entrée lua ou python
        endif
        

        entry #12

        written by moshikoi
        submitted at
        0 likes

        guesses
        comments 0

        post a comment


        main.cpp ASCII text
          1
          2
          3
          4
          5
          6
          7
          8
          9
         10
         11
         12
         13
         14
         15
         16
         17
         18
         19
         20
         21
         22
         23
         24
         25
         26
         27
         28
         29
         30
         31
         32
         33
         34
         35
         36
         37
         38
         39
         40
         41
         42
         43
         44
         45
         46
         47
         48
         49
         50
         51
         52
         53
         54
         55
         56
         57
         58
         59
         60
         61
         62
         63
         64
         65
         66
         67
         68
         69
         70
         71
         72
         73
         74
         75
         76
         77
         78
         79
         80
         81
         82
         83
         84
         85
         86
         87
         88
         89
         90
         91
         92
         93
         94
         95
         96
         97
         98
         99
        100
        101
        102
        103
        104
        105
        106
        107
        108
        109
        110
        111
        112
        113
        114
        115
        116
        117
        118
        119
        120
        121
        122
        123
        124
        125
        126
        127
        128
        129
        130
        131
        132
        133
        134
        135
        136
        137
        138
        139
        140
        141
        142
        143
        144
        145
        146
        147
        148
        149
        150
        151
        152
        153
        154
        155
        156
        157
        158
        159
        160
        161
        162
        163
        164
        165
        166
        167
        168
        169
        170
        171
        172
        173
        174
        175
        176
        177
        178
        179
        180
        181
        #include <cstddef>
        #include <iostream>
        #include <limits>
        #include <memory>
        #include <stdexcept>
        #include <string>
        #include <type_traits>
        #include <utility>
        
        enum class Color {
        	None = 0,
        	White = 1,
        	Black = 2,
        };
        
        Color
        opposite(Color color) {
        	return color == Color::White ? Color::Black : Color::White;
        }
        
        class Board {
        	static constexpr auto transposition_table_size = 2 << 10;
        	static constexpr auto win_score = 10000;
        
        	Color currentColor;
        	int height[7];
        	Color grid[7][6];
        
        	struct Transposition {
        		bool valid;
        		int score;
        		std::size_t hash;
        	};
        
        	std::unique_ptr<Transposition[]> transposition_table;
        
          public:
        	Board() : height{}, grid{{Color::None}}, currentColor{Color::White} { transposition_table = std::make_unique<Transposition[]>(transposition_table_size); }
        
        	int get_best_move() {
        		int bestColumn = 0;
        		int bestScore = -win_score;
        
        		for (int column = 0; column < 7; ++column) {
        			if (height[column] == 6) {
        				continue;
        			}
        			drop(column);
        			int score = is_win(opposite(currentColor), column, height[column] - 1) ? win_score : -negamax(6, -win_score, win_score);
        			undrop(column);
        
        			if (score > bestScore) {
        				bestColumn = column;
        				bestScore = score;
        			}
        		}
        
        		return bestColumn;
        	}
        
        	void drop(int column) {
        		auto &columnHeight = height[column];
        		if (columnHeight >= 6) {
        			throw std::runtime_error{"Attempted to drop a tile on a full column"};
        		}
        		grid[column][columnHeight] = currentColor;
        		currentColor = opposite(currentColor);
        		++columnHeight;
        	}
        	void undrop(int column) {
        		auto &columnHeight = height[column];
        		--columnHeight;
        		grid[column][columnHeight] = Color::None;
        		currentColor = opposite(currentColor);
        	}
        
        	int negamax(int depth, int alpha, int beta) {
        		auto const hash = state_hash();
        		auto &entry = transposition_table[hash % transposition_table_size];
        		if (entry.valid && entry.hash == hash) {
        			return entry.score;
        		}
        		if (depth < 0) {
        			return eval();
        		}
        
        		for (int column = 0; column < 7; ++column) {
        			if (height[column] == 6) {
        				continue;
        			}
        			drop(column);
        			int score = is_win(opposite(currentColor), column, height[column] - 1) ? win_score : -negamax(depth - 1, -beta, -alpha);
        			undrop(column);
        			if (score > beta) {
        				return beta;
        			}
        			if (score > alpha) {
        				alpha = score;
        			}
        		}
        
        		entry.valid = true;
        		entry.hash = hash;
        		entry.score = alpha;
        
        		return alpha;
        	}
        
        	int eval() { return advantage(currentColor) - advantage(opposite(currentColor)); }
        
        	int advantage(Color color) {
        		int total = 0;
        		for (int column = 0; column < 7; ++column) {
        			int count = 0;
        			for (int row = height[column] - 1; row >= 0 && grid[column][row] == color; --row) {
        				++count;
        			}
        
        			total += count;
        		}
        
        		return total;
        	}
        
        	bool is_win(Color color, int column, int row) {
        		std::pair<int, int> deltas[] = {
        		    {0, 1}, {0, -1}, {1, 0}, {-1, 0}, {1, 1}, {1, -1}, {-1, 1}, {-1, -1},
        		};
        
        		for (auto const &[deltaX, deltaY] : deltas) {
        			for (int offset = 0; offset < 4; ++offset) {
        				auto const offsetColumn = column + deltaY * offset;
        				auto const offsetRow = row + deltaX * offset;
        				if (offsetColumn < 0 || offsetColumn >= 7 || offsetRow < 0 || offsetRow >= 6 || grid[offsetColumn][offsetRow] != color) {
        					goto next;
        				}
        			}
        			return true;
        		next:
        			continue;
        		}
        
        		return false;
        	}
        
        	std::size_t state_hash() {
        		std::size_t hash = 0;
        		for (int column = 0; column < 7; ++column) {
        			for (int row = 5; row >= 0; --row) {
        				hash = hash * 3 + static_cast<std::underlying_type_t<Color>>(grid[column][row]);
        			}
        		}
        		return hash;
        	}
        };
        
        int
        main(int argc, char const **argv) {
        	char turn;
        	std::cin >> turn;
        
        	Board board{};
        
        	try {
        		switch (turn) {
        			while (true) {
        			case 'f': {
        				int move = board.get_best_move();
        				std::cout << move << std::endl;
        				board.drop(move);
        				[[fallthrough]];
        			}
        			case 's': {
        				int move;
        				std::cin >> move;
        				board.drop(move);
        			}
        			}
        		}
        	} catch (std::exception const ex) { std::cerr << ex.what() << std::endl; }
        }
        

        entry #13

        written by razetime
        submitted at
        1 like

        guesses
        comments 0

        post a comment


        connectfork.swf Unicode text, UTF-8 text, with CRLF line terminators
          1
          2
          3
          4
          5
          6
          7
          8
          9
         10
         11
         12
         13
         14
         15
         16
         17
         18
         19
         20
         21
         22
         23
         24
         25
         26
         27
         28
         29
         30
         31
         32
         33
         34
         35
         36
         37
         38
         39
         40
         41
         42
         43
         44
         45
         46
         47
         48
         49
         50
         51
         52
         53
         54
         55
         56
         57
         58
         59
         60
         61
         62
         63
         64
         65
         66
         67
         68
         69
         70
         71
         72
         73
         74
         75
         76
         77
         78
         79
         80
         81
         82
         83
         84
         85
         86
         87
         88
         89
         90
         91
         92
         93
         94
         95
         96
         97
         98
         99
        100
        101
        // right into the wall socket 🥺
        
        extension String: Error {}
        let verbose: Bool = CommandLine.arguments.last == "-v"
        
        func display(board: [[Int]]) {
          for (index, row) in board.enumerated() {
            for col in row {
              print("│",terminator:"")
              if col == 0 {
                print(" ",terminator:"")
              } else if col == 1 {
                print("①",terminator:"")
              } else {
                print("❶",terminator:"")
              }
            }
            print("│")
            if index == 5 {
              print("└─┴─┴─┴─┴─┴─┴─┘")
            } else {
              print("├─┼─┼─┼─┼─┼─┼─┤")
            }
          }
        }
        
        func move(board: inout [[Int]], depth: inout [Int], player: Int, col: Int) {
          board[depth[col]][col] = player
          depth[col] -= 1
        }
        
        func win(board: [[Int]], depth: [Int], player: Int, col: Int) -> Bool {
          for (moveRow, moveCol) in [(0,1),(1,0),(-1,0),(0,-1),(1,1),(1,-1),(-1,-1),(-1,1)]{
            if (0..<4).allSatisfy({board[depth[col] + $0 * moveRow][col + $0 * moveCol] == player}) {
              return true
            }
          }
          return false
        }
        
        
        var board: [[Int]] = [[Int]](repeating: [Int](repeating: 0, count: 7), count: 6)
        var depth: [Int] = [Int](repeating: 5, count: 7)
        var lPlayer: Int = 2
        var lMove: Int = 0
        if "f" == readLine() {
          let cMove: Int = (0..<7).filter({depth[$0] > 0}).randomElement()!
          print(cMove+1)
          move(board: &board, depth: &depth, player: 2, col: cMove)
          lPlayer = 2
          lMove = cMove
        }
        while !win(board: board, depth: depth, player: lPlayer, col: lMove) {
          switch lPlayer {
            case 2:
              if verbose {
                print("Enter move: ", terminator: "")
              }
              if let StrMove = readLine() {
                if let tMove = Int(StrMove) {
                  lMove = tMove-1
                }
              } else {
                if verbose {
                  print("invalid move! :3")
                }
                continue
              }
              if depth[lMove] == 0 {
                if verbose {
                  print("Column \(lMove) is full.")
                }
                continue
              }
              move(board: &board, depth: &depth, player: 1, col: lMove)
              lPlayer = 1
            case 1:
              if verbose {
                print("Computer move: ", terminator: "")
              }
              let cMove: Int = (0..<7).filter({depth[$0] > 0}).randomElement()!
              print(cMove+1)
              if verbose {
                display(board: board)
              }
              move(board: &board, depth: &depth, player: 2, col: cMove)
              lPlayer = 2
              lMove = cMove
            default:
              print("zoinks!")
              throw "oopsies!"
          }
        }
        switch lPlayer {
          case 1:
            print("You Win!")
          case 2:
            print("Computer Wins!")
          default:
            print("]¥ÍH›ØáôPS Wins!")
        }
        

        entry #14

        written by soup girl
        submitted at
        0 likes

        guesses
        comments 0

        post a comment


        4.py ASCII text, with CRLF line terminators
        1
        2
        3
        4
        5
        6
        import random
        if input() == 's': input()
        while True:
            # the right column is cursed, we do not go there
            print(random.randint(1,6))
            input()
        

        entry #15

        written by jetison333
        submitted at
        0 likes

        guesses
        comments 0

        post a comment


        connectFour.py ASCII text, with CRLF line terminators
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
        44
        45
        46
        47
        48
        49
        50
        51
        52
        53
        54
        55
        56
        57
        58
        59
        60
        61
        62
        63
        64
        65
        66
        67
        68
        69
        70
        71
        72
        73
        74
        75
        76
        77
        78
        79
        80
        81
        82
        83
        84
        85
        86
        87
        88
        89
        90
        91
        92
        93
        94
        95
        96
        97
        98
        def stripList(lst):
            return [x for x in lst if not x is None]
        
        def endState():
            for x, col in enumerate(board):
                for y, space in enumerate(col):
                    if space != 0:
                        if (x + 3 < len(board) and space == board[x+1][y] == board[x+2][y] == board[x+3][y]):
                            return space
                        if (y + 3 < len(board[0]) and space == board[x][y+1] == board[x][y+2] == board[x][y+3]):
                            return space
                        if (x + 3 < len(board) and y + 3 < len(board[0]) and space == board[x+1][y+1] == board[x+2][y+2] == board[x+3][y+3]):
                            return space
                        if (x + 3 < len(board) and y - 3 >= 0 and space == board[x+1][y-1] == board[x+2][y-2] == board[x+3][y-3]):
                            return space
            return 0
        
        def updateBoard(move, player):
            moveStack.append(move)
            if player == max:
                board[move][board[move].index(0)] = 1
            else:
                board[move][board[move].index(0)] = -1
        
        def undo():
            move = moveStack.pop()
            if 0 in board[move]:
                board[move][board[move].index(0) - 1] = 0
            else:
                board[move][-1] = 0
        
        def check(arr):
            return 0 in arr and ((1 in arr) ^ (-1 in arr))
        
        def evaluate4(arr):
            if 1 in arr:
                return 10 ** (arr.count(1) - 1)
            return -(10 ** (arr.count(-1) - 1))
        
        def evaluateBoard():
            if (winner := endState()) != 0:
                return winner * 100000
            total = 0
            for x, col in enumerate(board):
                for y, space in enumerate(col):
                    if (x + 3 < len(board)):
                        right = [space, board[x+1][y], board[x+2][y], board[x+3][y]]
                        if check(right):
                            total += evaluate4(right)
                    if (y + 3 < len(board[0])):
                        up = [space, board[x][y+1], board[x][y+2], board[x][y+3]]
                        if check(up):
                            total += evaluate4(up)
                    if (x + 3 < len(board) and y + 3 < len(board[0])):
                        upright = [space, board[x+1][y+1], board[x+2][y+2], board[x+3][y+3]]
                        if check(upright):
                            total += evaluate4(upright)
                    if (x + 3 < len(board) and y - 3 >= 0):
                        downright = [space, board[x+1][y-1], board[x+2][y-2], board[x+3][y-3]]
                        if check(downright):
                            total += evaluate4(downright)
            return total
                
        def evaluateMove(move, player, depth = 0):
            global board
            if not 0 in board[move]:
                return None
            updateBoard(move, min if player == max else max)
            if (winner := endState()) != 0:
                returnVal = winner * 100000
            elif depth > 4: #tune this if it takes to long/short
                returnVal = evaluateBoard()
            else:
                moves = [evaluateMove(x, min if player == max else max, depth+1) for x in range(7)]
                if all(move is None for move in moves):
                    returnVal = None
                else:
                    returnVal = player(stripList(moves))
            undo()
            return returnVal
        
        def move(player):
            moves = [evaluateMove(x, min if player == max else max) for x in range(7)]
            choosenMove = moves.index(player(stripList(moves)))
            updateBoard(choosenMove, player)
            return choosenMove
        
        board = [[0 for _ in range(6)] for _ in range(7)]
        moveStack = []
        
        side = input()
        player = max
        if side == "f":
            player = min
            print(move(player) + 1)
        while endState() == 0:
            updateBoard(int(input()) - 1, min if player == max else max)
            print(move(player) + 1)