diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..71b9c9b --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2018 Jeremy Rand + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/a2sudoku.xcodeproj/project.pbxproj b/a2sudoku.xcodeproj/project.pbxproj index f077549..a19f773 100644 --- a/a2sudoku.xcodeproj/project.pbxproj +++ b/a2sudoku.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 9D3B394020E082580055431C /* mouseWrapper.c in Sources */ = {isa = PBXBuildFile; fileRef = 9D3B393E20E082580055431C /* mouseWrapper.c */; }; 9D3FF4AF20DA05C2006A5F8A /* AppleCommander.jar in Frameworks */ = {isa = PBXBuildFile; fileRef = 9D3FF4AE20DA05C2006A5F8A /* AppleCommander.jar */; }; 9D3FF4B120DA05C2006A5F8A /* createDiskImage in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9D3FF4B020DA05C2006A5F8A /* createDiskImage */; }; 9D3FF4B320DA05C2006A5F8A /* DevApple.vii in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9D3FF4B220DA05C2006A5F8A /* DevApple.vii */; }; @@ -44,6 +45,9 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 9D3B393D20E0821B0055431C /* LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE; sourceTree = ""; }; + 9D3B393E20E082580055431C /* mouseWrapper.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = mouseWrapper.c; sourceTree = ""; }; + 9D3B393F20E082580055431C /* mouseWrapper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = mouseWrapper.h; sourceTree = ""; }; 9D3FF4A620DA05C2006A5F8A /* doNotBuild */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = doNotBuild; sourceTree = BUILT_PRODUCTS_DIR; }; 9D3FF4AE20DA05C2006A5F8A /* AppleCommander.jar */ = {isa = PBXFileReference; lastKnownFileType = archive.jar; name = AppleCommander.jar; path = make/AppleCommander.jar; sourceTree = ""; }; 9D3FF4B020DA05C2006A5F8A /* createDiskImage */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; name = createDiskImage; path = make/createDiskImage; sourceTree = ""; }; @@ -85,6 +89,7 @@ children = ( 9D3FF4CA20DA05E4006A5F8A /* a2sudoku.png */, 9D3FF4C920DA05E3006A5F8A /* README.md */, + 9D3B393D20E0821B0055431C /* LICENSE */, 9D3FF4A820DA05C2006A5F8A /* a2sudoku */, 9D3FF4A720DA05C2006A5F8A /* Products */, ); @@ -107,6 +112,8 @@ 9D3FF4CC20DA05F2006A5F8A /* main.c */, 9D3FF4CF20DA05F3006A5F8A /* ui.c */, 9D3FF4D420DA05F3006A5F8A /* ui.h */, + 9D3B393E20E082580055431C /* mouseWrapper.c */, + 9D3B393F20E082580055431C /* mouseWrapper.h */, 9D3FF4DA20DA0622006A5F8A /* puzzles */, 9D3FF4AD20DA05C2006A5F8A /* make */, 9D3FF4BE20DA05C2006A5F8A /* Supporting Files */, @@ -227,6 +234,7 @@ 9D3FF4D920DA05F3006A5F8A /* Makefile in Sources */, 9D3FF4D620DA05F3006A5F8A /* main.c in Sources */, 9D3FF4D820DA05F3006A5F8A /* game.c in Sources */, + 9D3B394020E082580055431C /* mouseWrapper.c in Sources */, 9D3FF4D720DA05F3006A5F8A /* ui.c in Sources */, 9D3FF4D520DA05F3006A5F8A /* puzzles.c in Sources */, ); diff --git a/a2sudoku.xcodeproj/project.xcworkspace/xcuserdata/jrand.xcuserdatad/UserInterfaceState.xcuserstate b/a2sudoku.xcodeproj/project.xcworkspace/xcuserdata/jrand.xcuserdatad/UserInterfaceState.xcuserstate index 726a0a8..2563954 100644 Binary files a/a2sudoku.xcodeproj/project.xcworkspace/xcuserdata/jrand.xcuserdatad/UserInterfaceState.xcuserstate and b/a2sudoku.xcodeproj/project.xcworkspace/xcuserdata/jrand.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/a2sudoku/Makefile b/a2sudoku/Makefile index 843f2d0..b93ca55 100644 --- a/a2sudoku/Makefile +++ b/a2sudoku/Makefile @@ -151,7 +151,7 @@ DRIVERS += hiresgr # If you want to link the mouse driver with your executable, # uncomment the next line. -# DRIVERS += mouse +DRIVERS += mouse # # To use the mouse driver, add code which looks like this to your # project: diff --git a/a2sudoku/make/V2Make.scpt b/a2sudoku/make/V2Make.scpt index 43f0fd9..11e20ee 100644 Binary files a/a2sudoku/make/V2Make.scpt and b/a2sudoku/make/V2Make.scpt differ diff --git a/a2sudoku/mouseWrapper.c b/a2sudoku/mouseWrapper.c new file mode 100644 index 0000000..c074260 --- /dev/null +++ b/a2sudoku/mouseWrapper.c @@ -0,0 +1,79 @@ +// +// mouseWrapper.c +// a2sudoku +// +// Created by Jeremy Rand on 2018-06-24. +// Copyright © 2018 Jeremy Rand. All rights reserved. +// + +#include "mouseWrapper.h" +#include "drivers/a2_mouse_drv.h" + +// Defines and macros + +#define MOUSE_POS_SHIFT 4 +#define MOUSE_GRID_SIZE (BOARD_SIZE << MOUSE_POS_SHIFT) + + +// Globals + +static tMouseCallback gCursorPosCallback = NULL; +static bool gMouseInstalled = false; +static bool gMouseInPoll = false; +static struct mouse_box gMouseBox = { 0, 0, MOUSE_GRID_SIZE - 1, MOUSE_GRID_SIZE - 1 }; + + +// Implementation + +bool initMouse(tMouseCallback callback) +{ + if (!gMouseInstalled) { + if (mouse_install(&mouse_def_callbacks, &a2_mouse_drv) == 0) { + gMouseInstalled = true; + + mouse_setbox(&gMouseBox); + moveMouseToPos(0, 0); + } + } + + gCursorPosCallback = callback; + + return gMouseInstalled; +} + + +void shutdownMouse(void) +{ + if (gMouseInstalled) { + mouse_uninstall(); + gMouseInstalled = false; + } +} + + +void pollMouse(void) +{ + struct mouse_info mouseInfo; + + if (!gMouseInstalled) + return; + + mouse_info(&mouseInfo); + + gMouseInPoll = true; + gCursorPosCallback(mouseInfo.pos.x >> MOUSE_POS_SHIFT, + mouseInfo.pos.y >> MOUSE_POS_SHIFT); + gMouseInPoll = false; +} + + +void moveMouseToPos(tPos newX, tPos newY) +{ + if (!gMouseInstalled) + return; + + if (gMouseInPoll) + return; + + mouse_move(newX << MOUSE_POS_SHIFT, newY << MOUSE_POS_SHIFT); +} diff --git a/a2sudoku/mouseWrapper.h b/a2sudoku/mouseWrapper.h new file mode 100644 index 0000000..82add86 --- /dev/null +++ b/a2sudoku/mouseWrapper.h @@ -0,0 +1,30 @@ +// +// mouseWrapper.h +// a2sudoku +// +// Created by Jeremy Rand on 2018-06-24. +// Copyright © 2018 Jeremy Rand. All rights reserved. +// + +#ifndef _GUARD_PROJECTa2sudoku_FILEmouseWrapper_ +#define _GUARD_PROJECTa2sudoku_FILEmouseWrapper_ + +#include + +#include "puzzles.h" + + +// Typedefs + +typedef void (*tMouseCallback)(tPos newX, tPos newY); + + +// API + +extern bool initMouse(tMouseCallback callback); +extern void shutdownMouse(void); +extern void pollMouse(void); +extern void moveMouseToPos(tPos newX, tPos newY); + + +#endif /* define _GUARD_PROJECTa2sudoku_FILEmouseWrapper_ */ diff --git a/a2sudoku/ui.c b/a2sudoku/ui.c index 4fcc953..dbc34c8 100644 --- a/a2sudoku/ui.c +++ b/a2sudoku/ui.c @@ -16,6 +16,7 @@ #include "game.h" #include "ui.h" +#include "mouseWrapper.h" #include "drivers/a2_hires_drv.h" @@ -118,6 +119,31 @@ void drawGrid(void) } +void setCursorPos(tPos newX, tPos newY) +{ + tPos oldX = cursorX; + tPos oldY = cursorY; + + if (newX >= BOARD_SIZE) + newX = BOARD_SIZE - 1; + + if (newY >= BOARD_SIZE) + newY = BOARD_SIZE - 1; + + if ((cursorX == newX) && + (cursorY == newY)) + return; + + cursorX = newX; + cursorY = newY; + + refreshPos(cursorX, cursorY); + refreshPos(oldX, oldY); + + moveMouseToPos(cursorX, cursorY); +} + + void initUI(void) { static bool tgi_inited = false; @@ -131,6 +157,8 @@ void initUI(void) tgi_init(); tgi_inited = true; + + initMouse(setCursorPos); } @@ -166,6 +194,7 @@ void shutdownUI(void) { // Uninstall drivers tgi_uninstall(); + shutdownMouse(); } @@ -269,8 +298,8 @@ void displayInstructions(void) "\n" "The goal is to get the numbers from 1 to" "9 uniquely in each column, row and 3x3\n" - "subsquare. Move the cursor with I-J-K-L" - "or the arrow keys. Press a number key\n" + "subsquare. Move the cursor with arrow\n" + "keys, IJKM or mouse. Press a number key" "to enter a value. Press a number key\n" "while holding shift or open apple to\n" "toggle a scratch value. Press 0 to\n" @@ -592,191 +621,180 @@ bool playGame(void) graphicsMode(); while (true) { - bool shouldNotBeep = true; + pollMouse(); - if (isPuzzleSolved()) { - youWon(); - return true; - } - - ch = cgetc(); - - switch (ch) { - case 'h': - case 'H': - textMode(); - displayInstructions(); - graphicsMode(); - break; - - case 'o': - case 'O': - textMode(); - if (setOptions()) - refreshAllPos(); - graphicsMode(); - break; - - case 'r': - case 'R': - shouldSave = false; - restartGame(); - break; - - case 'n': - case 'N': + if (kbhit()) { + bool shouldNotBeep = true; + ch = cgetc(); + + switch (ch) { + case 'h': + case 'H': + textMode(); + displayInstructions(); + graphicsMode(); + break; + + case 'o': + case 'O': + textMode(); + if (setOptions()) + refreshAllPos(); + graphicsMode(); + break; + + case 'r': + case 'R': + shouldSave = false; + restartGame(); + break; + + case 'n': + case 'N': + return true; + + case 'q': + case 'Q': + case CH_ESC: + shutdownUI(); + if (shouldSave) { + clrscr(); + printf("\n\nSaving your puzzle so you can continue\n later..."); + saveGame(); + } + return false; + + case 'i': + case 'I': + case 0x0B: // Only defined with apple2enh targts, CH_CURS_UP: + if (cursorY != 0) { + setCursorPos(cursorX, cursorY - 1); + } else { + setCursorPos(cursorX, BOARD_SIZE - 1); + } + break; + + case 'j': + case 'J': + case CH_CURS_LEFT: + if (cursorX != 0) { + setCursorPos(cursorX - 1, cursorY); + } else { + setCursorPos(BOARD_SIZE - 1, cursorY); + } + break; + + case 'k': + case 'K': + case CH_CURS_RIGHT: + if (cursorX < BOARD_SIZE - 1) { + setCursorPos(cursorX + 1, cursorY); + } else { + setCursorPos(0, cursorY); + } + break; + + case 'm': + case 'M': + case 0x0A: // Only defined with apple2enh targts, CH_CURS_DOWN: + if (cursorY < BOARD_SIZE - 1) { + setCursorPos(cursorX, cursorY + 1); + } else { + setCursorPos(cursorX, 0); + } + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (*button0 > 127) + shouldNotBeep = toggleScratchValueAtPos(cursorX, cursorY, ch - '0'); + else + shouldNotBeep = setValueAtPos(cursorX, cursorY, ch - '0'); + if (shouldNotBeep) + shouldSave = true; + break; + + case '!': + shouldNotBeep = toggleScratchValueAtPos(cursorX, cursorY, 1); + if (shouldNotBeep) + shouldSave = true; + break; + + case '@': + shouldNotBeep = toggleScratchValueAtPos(cursorX, cursorY, 2); + if (shouldNotBeep) + shouldSave = true; + break; + + case '#': + shouldNotBeep = toggleScratchValueAtPos(cursorX, cursorY, 3); + if (shouldNotBeep) + shouldSave = true; + break; + + case '$': + shouldNotBeep = toggleScratchValueAtPos(cursorX, cursorY, 4); + if (shouldNotBeep) + shouldSave = true; + break; + + case '%': + shouldNotBeep = toggleScratchValueAtPos(cursorX, cursorY, 5); + if (shouldNotBeep) + shouldSave = true; + break; + + case '^': + shouldNotBeep = toggleScratchValueAtPos(cursorX, cursorY, 6); + if (shouldNotBeep) + shouldSave = true; + break; + + case '&': + shouldNotBeep = toggleScratchValueAtPos(cursorX, cursorY, 7); + if (shouldNotBeep) + shouldSave = true; + break; + + case '*': + shouldNotBeep = toggleScratchValueAtPos(cursorX, cursorY, 8); + if (shouldNotBeep) + shouldSave = true; + break; + + case '(': + shouldNotBeep = toggleScratchValueAtPos(cursorX, cursorY, 9); + if (shouldNotBeep) + shouldSave = true; + break; + + case 'u': + case 'U': + shouldNotBeep = undoLastMove(); + break; + + default: + shouldNotBeep = false; + break; + } + + if (!shouldNotBeep) { + printf("\007"); + } + + if (isPuzzleSolved()) { + youWon(); return true; - - case 'q': - case 'Q': - case CH_ESC: - shutdownUI(); - if (shouldSave) { - clrscr(); - printf("\n\nSaving your puzzle so you can continue\n later..."); - saveGame(); - } - return false; - - case 'i': - case 'I': - case 0x0B: // Only defined with apple2enh targts, CH_CURS_UP: - if (cursorY != 0) { - cursorY--; - refreshPos(cursorX, cursorY); - refreshPos(cursorX, cursorY + 1); - } else { - cursorY = BOARD_SIZE - 1; - refreshPos(cursorX, cursorY); - refreshPos(cursorX, 0); - } - break; - - case 'j': - case 'J': - case CH_CURS_LEFT: - if (cursorX != 0) { - cursorX--; - refreshPos(cursorX, cursorY); - refreshPos(cursorX + 1, cursorY); - } else { - cursorX = BOARD_SIZE - 1; - refreshPos(cursorX, cursorY); - refreshPos(0, cursorY); - } - break; - - case 'k': - case 'K': - case CH_CURS_RIGHT: - if (cursorX < BOARD_SIZE - 1) { - cursorX++; - refreshPos(cursorX, cursorY); - refreshPos(cursorX - 1, cursorY); - } else { - cursorX = 0; - refreshPos(cursorX, cursorY); - refreshPos(BOARD_SIZE - 1, cursorY); - } - break; - - case 'm': - case 'M': - case 0x0A: // Only defined with apple2enh targts, CH_CURS_DOWN: - if (cursorY < BOARD_SIZE - 1) { - cursorY++; - refreshPos(cursorX, cursorY); - refreshPos(cursorX, cursorY - 1); - } else { - cursorY = 0; - refreshPos(cursorX, cursorY); - refreshPos(cursorX, BOARD_SIZE - 1); - } - break; - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - if (*button0 > 127) - shouldNotBeep = toggleScratchValueAtPos(cursorX, cursorY, ch - '0'); - else - shouldNotBeep = setValueAtPos(cursorX, cursorY, ch - '0'); - if (shouldNotBeep) - shouldSave = true; - break; - - case '!': - shouldNotBeep = toggleScratchValueAtPos(cursorX, cursorY, 1); - if (shouldNotBeep) - shouldSave = true; - break; - - case '@': - shouldNotBeep = toggleScratchValueAtPos(cursorX, cursorY, 2); - if (shouldNotBeep) - shouldSave = true; - break; - - case '#': - shouldNotBeep = toggleScratchValueAtPos(cursorX, cursorY, 3); - if (shouldNotBeep) - shouldSave = true; - break; - - case '$': - shouldNotBeep = toggleScratchValueAtPos(cursorX, cursorY, 4); - if (shouldNotBeep) - shouldSave = true; - break; - - case '%': - shouldNotBeep = toggleScratchValueAtPos(cursorX, cursorY, 5); - if (shouldNotBeep) - shouldSave = true; - break; - - case '^': - shouldNotBeep = toggleScratchValueAtPos(cursorX, cursorY, 6); - if (shouldNotBeep) - shouldSave = true; - break; - - case '&': - shouldNotBeep = toggleScratchValueAtPos(cursorX, cursorY, 7); - if (shouldNotBeep) - shouldSave = true; - break; - - case '*': - shouldNotBeep = toggleScratchValueAtPos(cursorX, cursorY, 8); - if (shouldNotBeep) - shouldSave = true; - break; - - case '(': - shouldNotBeep = toggleScratchValueAtPos(cursorX, cursorY, 9); - if (shouldNotBeep) - shouldSave = true; - break; - - case 'u': - case 'U': - shouldNotBeep = undoLastMove(); - break; - - default: - shouldNotBeep = false; - break; - } - if (!shouldNotBeep) { - printf("\007"); + } + } }