// Connect IV — Play against a perfect AI // Minimax with alpha-beta pruning + center-first move ordering // You are X (player I), AI is O (player II) // Enter column as Roman numeral I-VII // Returns the bottommost empty row in col, or NVLLVS if full DEFINI find_slot(b, col) VT { DESIGNA ans VT NVLLVS DONICVM r VT I VSQVE VI FACE { SI b[(r - I) * VII + col] EST NVLLVS TVNC { DESIGNA ans VT r } } REDI(ans) } // Returns VERITAS if player has four in a row DEFINI est_victor(b, player) VT { DONICVM r VT I VSQVE VI FACE { DONICVM c VT I VSQVE IV FACE { DESIGNA idx VT (r - I) * VII + c SI b[idx] EST player ET b[idx + I] EST player ET b[idx + II] EST player ET b[idx + III] EST player TVNC { REDI(VERITAS) } } } DONICVM r VT I VSQVE III FACE { DONICVM c VT I VSQVE VII FACE { DESIGNA idx VT (r - I) * VII + c SI b[idx] EST player ET b[idx + VII] EST player ET b[idx + XIV] EST player ET b[idx + XXI] EST player TVNC { REDI(VERITAS) } } } DONICVM r VT I VSQVE III FACE { DONICVM c VT I VSQVE IV FACE { DESIGNA idx VT (r - I) * VII + c SI b[idx] EST player ET b[idx + VIII] EST player ET b[idx + XVI] EST player ET b[idx + XXIV] EST player TVNC { REDI(VERITAS) } } } DONICVM r VT I VSQVE III FACE { DONICVM c VT IV VSQVE VII FACE { DESIGNA idx VT (r - I) * VII + c SI b[idx] EST player ET b[idx + VI] EST player ET b[idx + XII] EST player ET b[idx + XVIII] EST player TVNC { REDI(VERITAS) } } } REDI(FALSITAS) } DEFINI print_board(b) VT { DICE("+---+---+---+---+---+---+---+") DONICVM r VT I VSQVE VI FACE { DESIGNA line VT "| " DONICVM c VT I VSQVE VII FACE { DESIGNA cell VT b[(r - I) * VII + c] SI cell EST I TVNC { DESIGNA line VT line & "X | " } ALVID SI cell EST II TVNC { DESIGNA line VT line & "O | " } ALVID { DESIGNA line VT line & ". | " } } DICE(line) } DICE("+---+---+---+---+---+---+---+") DICE(" I II III IV V VI VII") REDI(NVLLVS) } // Score a 4-cell window: positive favours AI (II), negative favours player (I). // Only scores windows that are not mixed (one side can still win them). DEFINI score_fenestram(a, b, c, d) VT { DESIGNA ai VT NVLLVS DESIGNA pl VT NVLLVS SI a EST II TVNC { DESIGNA ai VT ai + I } SI b EST II TVNC { DESIGNA ai VT ai + I } SI c EST II TVNC { DESIGNA ai VT ai + I } SI d EST II TVNC { DESIGNA ai VT ai + I } SI a EST I TVNC { DESIGNA pl VT pl + I } SI b EST I TVNC { DESIGNA pl VT pl + I } SI c EST I TVNC { DESIGNA pl VT pl + I } SI d EST I TVNC { DESIGNA pl VT pl + I } SI pl EST NVLLVS TVNC { SI ai EST III TVNC { REDI(V) } SI ai EST II TVNC { REDI(II) } } SI ai EST NVLLVS TVNC { SI pl EST III TVNC { REDI(NVLLVS - V) } SI pl EST II TVNC { REDI(NVLLVS - II) } } REDI(NVLLVS) } // Static board evaluation: scan all 69 windows of 4 cells. // Returns a score in roughly [-350, 350]; positive = AI advantage. DEFINI aestima(b) VT { DESIGNA score VT NVLLVS // Center column preference: each AI piece in column IV is worth +1 DONICVM r VT I VSQVE VI FACE { SI b[(r - I) * VII + IV] EST II TVNC { DESIGNA score VT score + I } } // Horizontal windows (6 rows x 4 starting columns = 24) DONICVM r VT I VSQVE VI FACE { DONICVM c VT I VSQVE IV FACE { DESIGNA idx VT (r - I) * VII + c DESIGNA score VT score + INVOCA score_fenestram(b[idx], b[idx + I], b[idx + II], b[idx + III]) } } // Vertical windows (3 starting rows x 7 columns = 21) DONICVM r VT I VSQVE III FACE { DONICVM c VT I VSQVE VII FACE { DESIGNA idx VT (r - I) * VII + c DESIGNA score VT score + INVOCA score_fenestram(b[idx], b[idx + VII], b[idx + XIV], b[idx + XXI]) } } // Diagonal up-right windows (3 starting rows x 4 starting columns = 12) DONICVM r VT I VSQVE III FACE { DONICVM c VT I VSQVE IV FACE { DESIGNA idx VT (r - I) * VII + c DESIGNA score VT score + INVOCA score_fenestram(b[idx], b[idx + VIII], b[idx + XVI], b[idx + XXIV]) } } // Diagonal up-left windows (3 starting rows x 4 starting columns = 12) DONICVM r VT I VSQVE III FACE { DONICVM c VT IV VSQVE VII FACE { DESIGNA idx VT (r - I) * VII + c DESIGNA score VT score + INVOCA score_fenestram(b[idx], b[idx + VI], b[idx + XII], b[idx + XVIII]) } } REDI(score) } // Minimax with alpha-beta pruning and depth-limited aestima evaluation. // depth = remaining search plies (counts down from a fixed budget). // Wins score ±(M + depth) so the search always prefers quicker wins and // delays losses; aestima values stay well within ±M so wins dominate. DEFINI minimax(b, depth, alpha, beta, maxi) VT { SI maxi TVNC { SI INVOCA est_victor(b, I) TVNC { REDI(NVLLVS - M - depth) } } ALVID { SI INVOCA est_victor(b, II) TVNC { REDI(M + depth) } } SI depth EST I TVNC { REDI(INVOCA aestima(b)) } DESIGNA col_order VT [IV, III, V, II, VI, I, VII] SI maxi TVNC { DESIGNA best VT NVLLVS - M - VII PER c IN col_order FACE { DESIGNA linea VT INVOCA find_slot(b, c) SI NON (linea EST NVLLVS) TVNC { DESIGNA b[(linea - I) * VII + c] VT II DESIGNA score VT INVOCA minimax(b, depth - I, alpha, beta, FALSITAS) DESIGNA b[(linea - I) * VII + c] VT NVLLVS SI score PLVS best TVNC { DESIGNA best VT score } SI best PLVS alpha TVNC { DESIGNA alpha VT best } SI beta MINVS alpha AVT beta EST alpha TVNC { ERVMPE } } } REDI(best) } ALVID { DESIGNA best VT M + VII PER c IN col_order FACE { DESIGNA linea VT INVOCA find_slot(b, c) SI NON (linea EST NVLLVS) TVNC { DESIGNA b[(linea - I) * VII + c] VT I DESIGNA score VT INVOCA minimax(b, depth - I, alpha, beta, VERITAS) DESIGNA b[(linea - I) * VII + c] VT NVLLVS SI score MINVS best TVNC { DESIGNA best VT score } SI best MINVS beta TVNC { DESIGNA beta VT best } SI beta MINVS alpha AVT beta EST alpha TVNC { ERVMPE } } } REDI(best) } } // Pick the best column for the AI (depth VI = 5 plies of lookahead) DEFINI ai_move(b) VT { DESIGNA col_order VT [IV, III, V, II, VI, I, VII] DESIGNA best_score VT NVLLVS - M - VII DESIGNA best_col VT IV PER c IN col_order FACE { DESIGNA linea VT INVOCA find_slot(b, c) SI NON (linea EST NVLLVS) TVNC { DESIGNA b[(linea - I) * VII + c] VT II DESIGNA score VT INVOCA minimax(b, VI, NVLLVS - M - VII, M + VII, FALSITAS) DESIGNA b[(linea - I) * VII + c] VT NVLLVS SI score PLVS best_score TVNC { DESIGNA best_score VT score DESIGNA best_col VT c } } } REDI(best_col) } // --- Board setup --- DESIGNA board VT [I VSQVE XLII] DONICVM i VT I VSQVE XLII FACE { DESIGNA board[i] VT NVLLVS } DESIGNA moves VT NVLLVS DESIGNA game_over VT FALSITAS DICE("=== CONNECT IV ===") DICE("You are X. AI is O.") DICE("Enter column as Roman numeral (I-VII).") DICE("") DVM game_over FACE { EVERRO() INVOCA print_board(board) DICE("Your move:") DESIGNA col VT AVDI_NVMERVS() SI col PLVS VII TVNC { DICE("Invalid column! Enter I through VII.") CONTINVA } DESIGNA linea VT INVOCA find_slot(board, col) SI linea EST NVLLVS TVNC { DICE("Column full! Try another.") CONTINVA } DESIGNA board[(linea - I) * VII + col] VT I DESIGNA moves VT moves + I SI INVOCA est_victor(board, I) TVNC { INVOCA print_board(board) DICE("You win!") DESIGNA game_over VT VERITAS CONTINVA } SI moves EST XLII TVNC { INVOCA print_board(board) DICE("Draw!") DESIGNA game_over VT VERITAS CONTINVA } DICE("AI is thinking...") DESIGNA col VT INVOCA ai_move(board) DESIGNA linea VT INVOCA find_slot(board, col) DICE("AI plays column " & col & ".") DESIGNA board[(linea - I) * VII + col] VT II DESIGNA moves VT moves + I SI INVOCA est_victor(board, II) TVNC { INVOCA print_board(board) DICE("AI wins!") DESIGNA game_over VT VERITAS CONTINVA } SI moves EST XLII TVNC { INVOCA print_board(board) DICE("Draw!") DESIGNA game_over VT VERITAS } }