Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ------------------------------------------------------------------------------
- -- kalah.lua --
- -- An implementation of Kalah (the variation of mancala most familiar to --
- -- Americans) in OpenComputers. Supports one or two players, with an --
- -- AI opponent of varying difficulty. --
- ------------------------------------------------------------------------------
- local component = require("component")
- local event = require("event")
- local keyboard = require("keyboard")
- local term = require("term")
- local keys = keyboard.keys
- local gpu = component.gpu
- local screenWidth, screenHeight = gpu.getResolution()
- -- Make sure we have enough screen real estate.
- local originalScreenWidth, originalScreenHeight = screenWidth, screenHeight
- do
- if (screenWidth < 50) or (screenHeight < 16) then
- -- The screen's too small!
- local maxWidth, maxHeight = gpu.maxResolution()
- if (maxWidth < 50) or (maxHeight < 16) then
- -- Is this a robot or something?
- print("Kalah requires a minimum screen resolution of 50 x 16. Upgrade \z
- your monitor and graphics card and try again.")
- os.exit()
- else
- if (maxWidth >= 80) and (maxHeight >=25) then
- -- We can run at tier 2 resolution.
- screenWidth, screenHeight = 80, 25
- else
- screenWidth, screenHeight = 50, 16
- end
- gpu.setResolution(screenWidth, screenHeight)
- end
- end
- end
- local players = 0 -- So this can be accessed by functions.
- local totalSeeds = 0
- -- A collection of useful strings for various players.
- local usefulStrings = {}
- usefulStrings.who = {"Player 1", "Player 2", "I"}
- usefulStrings.has = {"has", "has", "have"}
- usefulStrings.is = {"is", "is", "am"}
- usefulStrings.s = {"s", "s", ""}
- -- And a way of accessing those strings.
- local function usefulString(player, desiredString)
- local stringIndex = player
- if (players == 1) and (player == 2) then stringIndex = 3 end
- return usefulStrings[desiredString][stringIndex]
- end
- -- Properly pluralize numbers.
- local function pluralize(number)
- if number ~= 1 then
- return "s"
- else
- return ""
- end
- end
- -- Find the sign of a number.
- local function sign(input)
- if input ~= 0 then
- return input / math.abs(input)
- else
- return 0
- end
- end
- -- Some comments the computer can make on moves.
- local colorCommentary = {}
- colorCommentary[1] = {"I think you're going to regret that.",
- "Are you sure? Well, okay...",
- "Heh heh heh heh.",
- "You're not very good at this game, are you?",
- "Ooooh, that's going to suck for you."}
- colorCommentary[2] = {"Hm. Not bad.",
- "You could have done better than that.",
- "Interesting.",
- "Well, it's not the worst you could have done.",
- "Let's see how that plays out, shall we?"}
- colorCommentary[3] = {"Oh, nice!",
- "That's a pretty good move.",
- "Yeah, I think I would have done that too.",
- "You've been practicing, haven't you?",
- "I'm impressed!"}
- -- Print a string, horizontally centered.
- local function centerPrint(stringToPad)
- local paddingNeeded = math.floor((screenWidth - stringToPad:len()) / 2)
- print(string.rep(" ", paddingNeeded) .. stringToPad)
- end
- -- cleanly exit the program, restoring the original resolution.
- local function allDone()
- gpu.setResolution(originalScreenWidth, originalScreenHeight)
- term.clear()
- print("Okay, see you next time!")
- os.exit()
- end
- -- Wait for a non-modifier keypress, optionally on a list of acceptable
- -- keypresses, and return it. Additionally, make a note of who pushed the
- -- key.
- local function getKeyPress(requiredKey)
- local char, lastTouched
- repeat
- _, _, char, _, lastTouched = event.pull("key_down")
- until (char ~= nil) and ((requiredKey == nil) or
- (requiredKey:find(string.char(char)) ~= nil))
- return string.char(char), lastTouched
- end
- -- As above, but if the user presses 'q', the program immediately ends.
- local function getKeyPressQuit(requiredKey)
- local char, lastTouched
- if requiredKey ~= nil then
- char, lastTouched = getKeyPress(requiredKey .. "q")
- else
- char, lastTouched = getKeyPress()
- end
- if char == "q" then allDone() end
- return char, lastTouched
- end
- -- Neatly format the number in a pit.
- local function pitString(pit)
- return string.format("%2d ", pit)
- end
- -- neatly format a fancy number in a pit.
- local fancyPit = {}
- do
- local maximumStones = 8 * 12
- for i = 0, 4 do fancyPit[i] = {} end
- for i = 0, maximumStones do fancyPit[0][i] = "╔═════╗" end
- for i = 0, maximumStones do fancyPit[4][i] = "╚═════╝" end
- fancyPit[1][0] = "║┌───┐║"
- fancyPit[2][0] = "║│ 0 │║"
- fancyPit[3][0] = "║└───┘║"
- fancyPit[1][1] = "║ ║"
- fancyPit[2][1] = "║ ∙ ║"
- fancyPit[3][1] = "║ ║"
- fancyPit[1][2] = "║ ║"
- fancyPit[2][2] = "║ ∙ ∙ ║"
- fancyPit[3][2] = "║ ║"
- fancyPit[1][3] = "║ ∙ ║"
- fancyPit[2][3] = "║ ║"
- fancyPit[3][3] = "║∙ ∙║"
- fancyPit[1][4] = "║∙ ∙║"
- fancyPit[2][4] = "║ ║"
- fancyPit[3][4] = "║∙ ∙║"
- fancyPit[1][5] = "║∙ ∙║"
- fancyPit[2][5] = "║ ∙ ║"
- fancyPit[3][5] = "║∙ ∙║"
- fancyPit[1][6] = "║ ∙ ∙ ║"
- fancyPit[2][6] = "║ ∙ ∙ ║"
- fancyPit[3][6] = "║ ∙ ∙ ║"
- fancyPit[1][7] = "║ ∙ ∙ ║"
- fancyPit[2][7] = "║∙ ∙ ∙║"
- fancyPit[3][7] = "║ ∙ ∙ ║"
- fancyPit[1][8] = "║∙ ∙ ∙║"
- fancyPit[2][8] = "║ ∙ ∙ ║"
- fancyPit[3][8] = "║∙ ∙ ∙║"
- fancyPit[1][9] = "║∙ ∙ ∙║"
- fancyPit[2][9] = "║∙ ∙ ∙║"
- fancyPit[3][9] = "║∙ ∙ ∙║"
- for i = 10, 8 * 12 do
- fancyPit[1][i] = "║┌───┐║"
- fancyPit[2][i] = "║│" .. string.sub(i, 1, 1) .. " " ..
- string.sub(i, 2, 2) .. "│║"
- fancyPit[3][i] = "║└───┘║"
- end
- end
- -- Make a table containing the current state of the board, neatly centered.
- local function boardTable(board)
- local output = {}
- local boardWidth
- if screenWidth < 64 then -- The plain-style board.
- boardWidth = 3 * 8
- table.insert(output, (" L K J I H G"))
- local tempString = " "
- for i = 13, 8, -1 do tempString = tempString .. pitString(board[i]) end
- table.insert(output, tempString)
- table.insert(output, pitString(board[14]) .. string.rep(" ", 3 * 6) ..
- pitString(board[7]))
- table.insert(output, "P2 " .. string.rep(" ", 3 * 6) .. "P1")
- tempString = " "
- for i = 1, 6 do tempString = tempString .. pitString(board[i]) end
- table.insert(output, tempString)
- table.insert(output, " A B C D E F")
- else -- The fancy-style board.
- boardWidth = 64
- table.insert(output,
- " L K J I H G")
- local tempString
- for i = 0, 4 do
- tempString = " "
- for j = 13, 8, -1 do
- tempString = tempString .. fancyPit[i][board[j]] .. " "
- end
- table.insert(output, tempString)
- end
- table.insert(output, "")
- for i = 0, 4 do
- table.insert(output, fancyPit[i][board[14]] .. string.rep(" ",
- 8 * 6 + 1) .. fancyPit[i][board[7]])
- end
- table.insert(output, " P 2 " .. string.rep(" ", 8 * 6) .. " P 1")
- for i = 0, 4 do
- tempString = " "
- for j = 1, 6 do
- tempString = tempString ..fancyPit[i][board[j]] .. " "
- end
- table.insert(output, tempString)
- end
- table.insert(output,
- " A B C D E F")
- end
- -- Now center the board.
- local centerPadding = string.rep(" ",
- math.floor((screenWidth - boardWidth) / 2))
- for i, j in pairs(output) do
- output[i] = centerPadding .. j
- end
- return output
- end
- -- Print the board.
- local function printBoard(board)
- print()
- for i, j in pairs(boardTable(board)) do print(j) end
- print()
- end
- -- Given a string and width, return a table of strings that wrap the string to
- -- the width.
- local function wrapText(textToWrap, width)
- local outputList = {}
- while textToWrap ~= "" do
- local nextNewLine = textToWrap:find("\n")
- if (nextNewLine ~= nil) and (nextNewLine <= width) then
- -- There's an explicit newline in the next width characters.
- table.insert(outputList, textToWrap:sub(1, nextNewLine - 1))
- textToWrap = textToWrap:sub(nextNewLine + 1)
- else
- if string.len(textToWrap) <= width then -- Last line.
- table.insert(outputList, textToWrap)
- textToWrap = ""
- else
- local lastSpace = textToWrap:sub(1, width):reverse():find(" ")
- if lastSpace == nil then
- -- The next word is longer than width characters, so we'll break it.
- table.insert(outputList, textToWrap:sub(1, width))
- textToWrap = textToWrap:sub(width + 1)
- else
- -- We'll break the line at the last space in width characters.
- table.insert(outputList, textToWrap:sub(1,width - lastSpace))
- textToWrap = textToWrap:sub(width - lastSpace + 2)
- end
- end
- end
- end
- return outputList
- end
- -- Print the instructions for Kalah, allowing forward and backward scrolling.
- local function printInstructions()
- local instructions1 = "(Press space or Enter to read more, backspace \z
- to read less, and Q to quit reading.)\n\nKalah is a game in \z
- the mancala family invented by William Julius Champion Jr. in 1940. It \z
- is the most familiar version of mancala to American audiences, and \z
- indeed most Americans would call it simply 'mancala'.\n\nKalah is \z
- played on a board with two rows, one for each player, each of which has \z
- six small pits, called houses. A large pit, called a kalah or store, is \z
- at each end of the board, one for each player.\n\nAt the beginning of \z
- each game, each of the twelve houses is filled with a number of seeds \z
- (usually three or four each). On your turn, you choose one of your \z
- houses that has seeds in it and 'sow' the seeds. To do so, you remove \z
- the seeds from that house, then go around the board counter-clockwise, \z
- depositing one seed in each pit along the way. (You skip over your \z
- opponent's store, which is on your left, but not your own store, on the \z
- right.)\n\nIf the last seed you sow lands in your store, you get an \z
- extra turn. There is no limit to how many extra turns you can get this \z
- way.\n\nIf the last seed you sow lands in one of your own empty houses, \z
- and your opponent has seeds in the house opposite that one, both your \z
- last seed and all of his seeds in that house are captured and placed in \z
- your store.\n\nWhen someone no longer has any seeds in any of his \z
- houses, the game ends. The other player moves all of his remaining \z
- seeds to his store, and the player with the most seeds in his store \z
- wins. The game also ends if one player gets more than half the seeds in \z
- his store, in which case he wins.\n\nIn a moment, I'll ask you if you \z
- want to play with one or two players. (I'll be your opponent if you \z
- choose a single-player game; if you play two-player, I'll spectate.) \z
- I'll also ask how smart you want me to be, which will affect both my \z
- own play and any comments I offer on yours. (Fair warning: I take up to \z
- six times longer to ponder the board between moves for each increase in \z
- intelligence. If it's looking like I won't finish my move this century, \z
- press 'Q' to quit and try again at a lower difficulty.) Then I'll \z
- ask how chatty you want me to be; I enjoy commenting on moves, but you \z
- can shut me up if you like. Last, I'll ask how many seeds you want in \z
- each house (up to 8).\n\nThe game board looks like this:"
- local instructions2 = "\nOn your turn, simply enter the letter of the \z
- house you want to move seeds from. The first player is at the bottom of \z
- the board (A-F); the second player (who would be me if you choose not \z
- to have a second living player) is at the top (G-L).\n\nTwo final \z
- details. First, the first player has a distinct advantage in Kalah. \z
- I'll always let you go first (I'm nice that way), but if you want to \z
- make the game more fair when you're playing someone else, you can use \z
- the 'pie rule'. That means that, after the first player's first move, \z
- the second player can decide to either continue playing or switch \z
- places with the first player (whose turn it will then be as the second \z
- player). It's up to you if you want to do that.\n\nSecond, if you want \z
- to quit the game at any time, type 'Q' for your move.\n\nI hope you \z
- have fun!"
- local instructions = wrapText(instructions1, screenWidth)
- table.insert(instructions, "")
- for i, j in pairs(boardTable({3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 0})) do
- table.insert(instructions, j)
- end
- for i, j in pairs(wrapText(instructions2, screenWidth)) do
- table.insert(instructions, j)
- end
- local line = 1
- repeat
- term.setCursor(1, 1)
- for i = line, math.min(line + screenHeight - 2, #instructions) do
- term.clearLine()
- print(instructions[i])
- end
- for i = #instructions + 1, screenHeight - 1 do
- term.clearLine()
- print()
- end
- if math.min(line + screenHeight - 2, #instructions) ~= #instructions then
- term.write("--more--")
- else
- term.write("--done--")
- end
- local key = getKeyPress(" \b\rq")
- if (key == " ") or (key == "\r") then
- if math.min(line + screenHeight - 2, #instructions) ==
- #instructions then -- We're done.
- line = #instructions
- else
- local forwardMove = line + screenHeight - 1
- if key == "\r" then forwardMove = line + 1 end
- line = math.min(forwardMove, #instructions - screenHeight + 2)
- end
- end
- if key == "\b" then line = math.max(1, line - screenHeight + 1) end
- if key == "q" then line = #instructions end
- term.clearLine()
- until line == #instructions
- end
- -- Clone a table.
- local function tableCopy(inputTable)
- local outputTable = {}
- for i, v in pairs(inputTable) do outputTable[i] = v end
- return outputTable
- end
- -- A map of move keystrokes to pits and vice versa.
- local pitLookup = {"A", "B", "C", "D", "E", "F", nil,
- "G", "H", "I", "J", "K", "L"}
- pitLookup.a = 1
- pitLookup.b = 2
- pitLookup.c = 3
- pitLookup.d = 4
- pitLookup.e = 5
- pitLookup.f = 6
- pitLookup.g = 8 -- Skipping a scoring pit.
- pitLookup.h = 9
- pitLookup.i = 10
- pitLookup.j = 11
- pitLookup.k = 12
- pitLookup.l = 13
- -- Given a board, a player, and a move, make the move and return the new
- -- board, the new player, and a message about the move.
- local function makeMove(board, player, move)
- local nextPlayer
- local newBoard = tableCopy(board)
- local seeds = newBoard[move]
- local message = usefulString(player, "who") .. " move" ..
- usefulString(player, "s") .. " " .. seeds .. " seed"
- if seeds > 1 then message = message .. "s" end
- message = message .. ", starting at house " .. pitLookup[move]
- newBoard[move] = 0
- for i = move + 1, move + seeds do -- Sowing the seeds.
- local j = (i - 1) % 14 + 1
- newBoard[j] = newBoard[j] + 1
- end
- local lastSeed = (move + seeds - 1) % 14 + 1
- if ((lastSeed == 7) and (player == 1)) or
- ((lastSeed == 14) and (player == 2)) then -- Player gets to go again.
- message = message .. ", and get" .. usefulString(player, "s") ..
- " to go again."
- nextPlayer = player
- elseif (newBoard[lastSeed] == 1) and (lastSeed > (player - 1) * 7) and
- (lastSeed < player * 7) and
- (newBoard[14 - lastSeed] > 0) then
- -- Player has captured seeds.
- local capturedPit = 14 - lastSeed
- local capturedSeeds = newBoard[capturedPit]
- message = message .. ", capturing " .. capturedSeeds .. " seed"
- if capturedSeeds > 1 then message = message .. "s" end
- message = message .. " from pit " .. pitLookup[capturedPit] .. "."
- newBoard[player * 7] = newBoard[player * 7] + capturedSeeds + 1
- newBoard[capturedPit] = 0
- newBoard[lastSeed] = 0
- nextPlayer = 3 - player
- else -- Boring end of turn.
- message = message .. "."
- nextPlayer = 3 - player
- end
- -- Is the game over at this point?
- for i = 1, 2 do
- if newBoard[i * 7] > totalSeeds / 2 then
- message = message .. "\n" .. usefulString(i, "who") .. " " ..
- usefulString(i, "has") ..
- " more than half of the seeds."
- nextPlayer = 0
- else
- local remainingStones = 0
- for j = 1, 6 do
- remainingStones = remainingStones + newBoard[(i - 1) * 7 + j]
- end
- if remainingStones == 0 then
- message = message .. "\n" .. usefulString(i, "who") ..
- " " .. usefulString(i, "is") .. " out of seeds. \n" ..
- usefulString(3 - i, "who") .. " collects all remaining \z
- seeds."
- for j = 1, 6 do
- newBoard[(3 - i) * 7] = newBoard[(3 - i) * 7] +
- newBoard[(2 - i) * 7 + j]
- newBoard[(2 - i) * 7 + j] = 0
- end
- nextPlayer = 0
- end
- end
- end
- return newBoard, nextPlayer, message
- end
- -- Give the player something to watch, and give the player a chance to end the
- -- game, while the computer ponders.
- local thinking = "Thinking..."
- local function itsThinking(percentComplete)
- local _, _, abortButton = event.pull(0, "key_down")
- if abortButton == string.byte("q") then allDone() end
- thinking = string.sub(thinking, 2) .. string.sub(thinking, 1, 1)
- term.clearLine()
- term.write(thinking .. string.format(" %2.2f%%", percentComplete * 100))
- end
- -- Consider the state of the board and return a table showing each
- -- possible move and the score for said move.
- local function evaluateBoard(board, player, intelligence, percentComplete,
- percentWidth)
- local moveTable = {}
- local numberOfMoves = 0
- for i = (player - 1) * 7 + 1, (player - 1) * 7 + 6 do
- if board[i] > 0 then numberOfMoves = numberOfMoves + 1 end
- end
- local moveNumber = -1
- for i = (player - 1) * 7 + 1, (player - 1) * 7 + 6 do
- if board[i] > 0 then -- A legal move.
- moveNumber = moveNumber + 1
- -- What's this move worth?
- local nextBoard, nextPlayer, nextMessage =
- makeMove(board, player, i)
- moveTable[i] = nextBoard[7] - nextBoard[14]
- if nextPlayer == 0 then -- This move ends the game.
- if moveTable[i] == 0 then
- moveTable[i] = 10000 -- Tie game.
- else
- moveTable[i] = 1100 * sign(moveTable[i]) -- 100% chance of win/loss.
- end
- else -- This move doesn't end the game.
- if intelligence > 1 then -- We have to go deeper.
- -- But don't lock up the computer.
- local newPercentComplete = percentComplete + percentWidth *
- moveNumber / numberOfMoves
- itsThinking(newPercentComplete)
- moveTable[i] = evaluateBoard(nextBoard, nextPlayer,
- intelligence - 1, newPercentComplete,
- percentWidth / numberOfMoves)
- if nextPlayer ~= 0 then -- moveTable[i] will be a table.
- -- Assume the next player will make the best of all possible
- -- moves UNLESS that move would cost the current player the game.
- -- In which case assume he plays well, but not perfect;
- -- if there's one winning move, give him an 80% chance of picking
- -- it, up to 100% if every move is a winning move. (This will keep
- -- the computer from just giving up in a bad situation.)
- local gameLosingMoves, totalMoves = 0, 0
- for i, j in pairs(moveTable[i]) do totalMoves = totalMoves + 1 end
- local likelyNextMove, likelyNextMoveScore
- for i, j in pairs(moveTable[i]) do
- if ((j >= 1000) and (player == 2) and (j ~= 10000)) or
- ((j <= -1000) and (player == 1)) then
- gameLosingMoves = gameLosingMoves + 1
- else
- if likelyNextMoveScore == nil then
- likelyNextMove, likelyNextMoveScore = i, j
- else
- if ((j > likelyNextMoveScore) and (player == 1)) or
- ((j < likelyNextMoveScore) and (player == 2)) or
- ((j == likelyNextMoveScore) and (math.random(2) == 2))
- then
- likelyNextMove, likelyNextMoveScore = i, j
- end
- end
- end
- end
- -- Did we find any losing moves?
- if gameLosingMoves ~= 0 then -- Yes.
- local losingOdds
- if gameLosingMoves == totalMoves then
- losingOdds = 100
- else
- losingOdds = 100 * (1 - 0.2 ^ gameLosingMoves)
- end
- likelyNextMoveScore = sign(player - 0.5) * (1000 + losingOdds)
- end
- -- We found the next player's move score, so...
- moveTable[i] = likelyNextMoveScore
- end
- end
- end
- end
- end
- return moveTable
- end
- -- The main program.
- term.clear()
- centerPrint("Kalah")
- centerPrint("by Fred M. Sloniker")
- print()
- term.write("Do you want instructions? (Y/N/Q) ", true)
- local choice = getKeyPressQuit("yn")
- print(string.upper(choice))
- print()
- if choice == "y" then
- printInstructions()
- print()
- end
- local anotherGame = ""
- repeat
- term.write("How many players? (1-2) ", true)
- players = getKeyPressQuit("12")
- print(players)
- term.write("How smart should I be? (1-9) ", true)
- local intelligence = getKeyPressQuit("123456789")
- print(intelligence)
- term.write("How chatty should I be? (0-9) ", true)
- local chattiness = getKeyPressQuit("0123456789")
- print(chattiness)
- term.write("How many seeds in each house? (1-8) ", true)
- local seedsPerPit, lastTouched = getKeyPressQuit("12345678")
- print(seedsPerPit)
- players, intelligence, seedsPerPit, chattiness = tonumber(players),
- tonumber(intelligence),
- tonumber(seedsPerPit),
- tonumber(chattiness)
- totalSeeds = seedsPerPit * 12
- usefulStrings.who[1] = lastTouched
- print("Okay! Let me get things started...")
- local board = {seedsPerPit, seedsPerPit, seedsPerPit, seedsPerPit,
- seedsPerPit, seedsPerPit, 0,
- seedsPerPit, seedsPerPit, seedsPerPit, seedsPerPit,
- seedsPerPit, seedsPerPit, 0}
- local gameOver = false
- local player = 1
- repeat
- printBoard(board)
- if player == 0 then -- The game is over.
- print("\nThe game is over.")
- gameOver = true
- for i = 1, 2 do
- print(usefulString(i, "who") .. " score" .. usefulString(i, "s") ..
- " " .. board[(i - 1) * 7 + 7] .. " point" ..
- pluralize(point) .. ".")
- end
- if board[7] > board[14] then
- print(usefulString(1, "who") .. " wins! Huzzah!")
- elseif board[7] < board [14] then
- if players == 1 then
- print("I win! Better luck next time.")
- else
- print(usefulString(2, "who") .. " wins! Huzzah!")
- end
- else
- term.write("It's a tie! ")
- if players == 1 then
- print("I'll get you next time.")
- else
- print("Better luck next time.")
- end
- end
- else -- The player does have a valid move.
- -- What does the computer think of the situation?
- local moveScores = evaluateBoard(board, player, intelligence, 0, 1)
- term.clearLine() -- Get rid of thinking glyph.
- if (player == 2) and (players == 1) then -- Computer's turn.
- print("My turn.")
- -- Find the best move from the scores.
- local bestMove, bestScore = next(moveScores, nil)
- for i, thisScore in pairs(moveScores) do
- if thisScore < bestScore then -- Low numbers are good in this case.
- bestMove, bestScore = i, thisScore
- end
- end
- local message = ""
- board, player, message = makeMove(board, player, bestMove)
- print(message)
- if player == 2 then -- The computer gets another turn, so wait.
- print("(Press a key to continue.)")
- local _ = getKeyPressQuit()
- end
- else -- Player's turn.
- local playerMove = ""
- repeat
- local legalMove = true
- term.write(usefulString(player, "who") .. "'s move? (", true)
- if player == 1 then print("A-F)") else print("G-L)") end
- if player == 1 then
- playerMove, lastTouched = getKeyPressQuit("abcdef0")
- else
- playerMove, lastTouched = getKeyPressQuit("ghijkl0")
- end
- usefulStrings.who[player] = lastTouched
- if playerMove == "0" then
- term.write("Cheater! Fine, here's what I think. ", true)
- for i, j in pairs(moveScores) do
- term.write(pitLookup[i] .. ": " .. j, true)
- if next(moveScores, i) ~= nil then term.write("; ", true) end
- end
- print()
- if player == 1 then
- term.write("Higher")
- else
- term.write("Lower")
- end
- print(" numbers are better for you.")
- legalMove = false
- end
- if board[pitLookup[playerMove]] == 0 then
- print("Illegal move: no stones in that pit.")
- legalMove = false
- end
- if not legalMove then printBoard(board) end
- until legalMove
- local message = ""
- -- What does the computer think about that move?
- local _, minScore = next(moveScores, nil)
- local maxScore = minScore
- for i, thisScore in pairs(moveScores) do
- if thisScore < minScore then minScore = thisScore end
- if thisScore > maxScore then maxScore = thisScore end
- end
- local rating = 2
- if minScore ~= maxScore then
- rating = math.min(math.floor((moveScores[pitLookup[playerMove]] -
- minScore) / (maxScore - minScore) * 3), 2) + 1
- end
- -- For player 2, lower ratings are better.
- if player == 2 then rating = 4 - rating end
- if math.random(0, 8) < chattiness then
- print(colorCommentary[rating][math.random(5)])
- end
- board, player, message = makeMove(board, player,
- pitLookup[playerMove])
- print(message)
- end
- end
- until gameOver
- print()
- term.write("Would you like to play again? (Y/N) ", true)
- anotherGame = getKeyPressQuit("yn")
- print(string.upper(anotherGame))
- until anotherGame == "n"
- allDone()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement